home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume1 / vnews / part2 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  62.0 KB

  1. From: decvax!vax135!hou3c!ka
  2. Date: Mon, 21 Jan 85 21:54:50 est
  3. Newsgroups: mod.sources
  4. Subject: Vnews part 2
  5.  
  6. # Welcome to vnews release 2.11-B 1/17/85.
  7. # This is part 2 out of 7.
  8. # Feed me into sh (NOT csh).
  9.  
  10. if test ! -d artfile
  11. then    mkdir artfile
  12. fi
  13.  
  14. if test ! -d lib
  15. then    mkdir lib
  16. fi
  17.  
  18. cat > artfile/ifuncs.c.10.2 <<\!E!O!F!
  19. /*
  20.  * ifuncs - functions used by inews.
  21.  */
  22.  
  23. #ifndef lint
  24. static char    *SccsId = "@(#)ifuncs.c    2.35    9/12/84";
  25. #endif !lint
  26.  
  27. #include "iparams.h"
  28. #include <errno.h>
  29.  
  30. /*
  31.  * Transmit this article to all interested systems.
  32.  */
  33.  
  34. #ifdef u370
  35. static struct srec srec;
  36. #endif
  37.  
  38. static struct hbuf h, hh;
  39.  
  40. broadcast()
  41. {
  42.     register char *nptr, *hptr;
  43.     register FILE *fp;
  44. #ifndef u370
  45.     struct srec srec;
  46. #endif
  47.     char sentbuf[BUFLEN];
  48.     int nsent = 0;
  49.  
  50.     /* h is a local copy of the header we can scribble on */
  51.     fp = xfopen(ARTICLE, "r");
  52.     if (hread(&h, fp, TRUE) == NULL)
  53.         xerror("Cannot reread article");
  54.     fclose(fp);
  55.  
  56.     strcpy(sentbuf, h.ident);
  57.     strcat(sentbuf, " sent to ");
  58.     nsent = 0;
  59.     /* break path into list of systems. */
  60.     hptr = nptr = h.path;
  61.     while (*hptr != '\0') {
  62.         if (index(NETCHRS, *hptr)) {
  63.             *hptr++ = '\0';
  64.             nptr = hptr;
  65.         } else
  66.             hptr++;
  67.     }
  68.     *nptr = '\0';
  69.  
  70.     /* loop once per system. */
  71.     lock();
  72.     s_openr();
  73.     while (s_read(&srec)) {
  74.         if (strncmp(srec.s_name, FULLSYSNAME, SNLN) == 0)
  75.             continue;
  76.         hptr = h.path;
  77.         while (*hptr != '\0') {
  78.             if (strncmp(srec.s_name, hptr, SNLN) == 0)
  79.                 goto contin;
  80.             while (*hptr++ != '\0')
  81.                 ;
  82.         }
  83.         if (ngmatch(h.nbuf, srec.s_nbuf)) {
  84.             if (h.distribution[0] == '\0' ||
  85.                 ngmatch(h.distribution, srec.s_nbuf) ||
  86.                 ngmatch(h.nbuf, h.distribution)) {
  87.                 if (transmit(&srec, xfopen(ARTICLE, "r"), 1)) {
  88.                     if (nsent)
  89.                         strcat(sentbuf, ", ");
  90.                     strcat(sentbuf, srec.s_name);
  91.                     nsent++;
  92.                 }
  93.             }
  94.         }
  95.     contin:;
  96.     }
  97.     if (nsent)
  98.         log(sentbuf);
  99.     s_close();
  100.     unlock();
  101. }
  102.  
  103. /*
  104.  * Transmit file to system.
  105.  */
  106. #define PROC 0004
  107. transmit(sp, ifp, maynotify)
  108. register struct srec *sp;
  109. register FILE *ifp;
  110. int maynotify;
  111. {
  112.     register FILE *ofp;
  113.     register int c;
  114.     register char *ptr;
  115.     char TRANS[BUFLEN];
  116.     char *argv[20];
  117.     register int pid;
  118.     extern char firstbufname[];
  119.  
  120. /* A:    afmt: the other machine runs an A news, so we xmit in A format */
  121.     int afmt = (index(sp->s_flags, 'A') != NULL);
  122. /* B:    use B format (this is the default - don't use this letter elsewise). */
  123. /* F:    append name to file */
  124.     int appfile = (index(sp->s_flags, 'F') != NULL);
  125. /* H:    history: expand %s into the history line (KSA) */
  126.     int history = (index(sp->s_flags, 'H') != NULL);  /* (6/18/84 KSA) */
  127. /* L:    local: don't send the article unless it was generated locally */
  128.     int local = (index(sp->s_flags, 'L') != NULL);
  129. /* N:    notify: don't send the article, just tell him we have it */
  130.     int notify = maynotify && (index(sp->s_flags, 'N') != NULL);
  131. /* S:    noshell: don't fork a shell to execute the xmit command */
  132.     int noshell = (index(sp->s_flags, 'S') != NULL);
  133. /* U:    useexist: use the -c option to uux to use the existing copy */
  134.     int useexist = (index(sp->s_flags, 'U') != NULL);
  135.  
  136.     if (local && mode == PROC) {
  137.         fclose(ifp);
  138.         return FALSE;
  139.     }
  140. #ifdef DEBUG
  141.     printf("Transmitting to '%s'\n", sp->s_name);
  142. #endif
  143.     if (!appfile && !useexist && !history) {    /* (6/18/84 KSA) */
  144.         if (hread(&hh, ifp, TRUE) == NULL) {
  145.             logerr("Bad header, not transmitting %s re %s to %s",
  146.                 hh.ident, hh.title, sp->s_name);
  147.             fclose(ifp);
  148.             return FALSE;
  149.         }
  150.         if (hh.nbuf[0] == '\0') {
  151.             fprintf(stderr, "Article not subscribed to by %s\n", sp->s_name);
  152.             fclose(ifp);
  153.             return FALSE;
  154.         }
  155.         sprintf(TRANS, "%s/trXXXXXX", SPOOL);
  156.     }
  157.  
  158.     if (notify) {
  159.         char oldid[50];
  160.         sprintf(hh.title, "ihave %s %s", hh.ident, FULLSYSNAME);
  161.         sprintf(hh.nbuf, "to.%s.ctl", sp->s_name);
  162.         strcpy(oldid, hh.ident);
  163.         getident(&hh);
  164.         log("tell %s about %s, notif. id %s",
  165.             sp->s_name, oldid, hh.ident);
  166.     }
  167.  
  168.     if (appfile) {
  169.         if (firstbufname[0] == '\0') {
  170.             extern char histline[];
  171.             localize("junk");
  172.             savehist(histline);
  173.             xerror("No file name to xmit from");
  174.         }
  175. #ifdef IHCC
  176.         sprintf(TRANS, "%s/%s/%s", logdir(HOME), BATCHDIR, sp->s_xmit);
  177.         ofp = fopen(TRANS, "a");
  178. #else
  179.         ofp = fopen(sp->s_xmit, "a");
  180. #endif
  181.         if (ofp == NULL)
  182.             xerror("Cannot append to %s", sp->s_xmit);
  183.         fprintf(ofp, "%s\n", firstbufname);
  184.         fclose(ofp);
  185.         fclose(ifp);
  186.         return TRUE;
  187.     }
  188.     else
  189. #ifdef UXMIT
  190.     if (useexist) {
  191.         if (firstbufname[0] == '\0')
  192.             xerror("No file name to xmit from");
  193.         if (*sp->s_xmit == '\0')
  194.             sprintf(bfr, UXMIT, sp->s_name, firstbufname);
  195.         else
  196.             sprintf(bfr, sp->s_xmit, firstbufname);
  197.         fclose(ifp);
  198.     } else
  199. #endif
  200.     if (history) {        /* (6/18/84 KSA) */
  201.         extern char histline[];
  202.         if (*sp->s_xmit == '\0')
  203.             xerror("no xmit command with H flag");
  204.         sprintf(bfr, sp->s_xmit, histline);
  205.     } else
  206.     {
  207.         ofp = xfopen(mktemp(TRANS), "w");
  208.         if (afmt)
  209.             ohwrite(&hh, ofp);
  210.         else
  211.             hwrite(&hh, ofp);
  212.         if (!notify)
  213.             while ((c = getc(ifp)) != EOF)
  214.                 putc(c, ofp);
  215.         fclose(ifp);
  216.         fclose(ofp);
  217.         if (*sp->s_xmit == '\0')
  218.             sprintf(bfr, DFTXMIT, sp->s_name, TRANS);
  219.         else
  220.             sprintf(bfr, "(%s) < %s", sp->s_xmit, TRANS);
  221.     }
  222.  
  223.     /* At this point, the command to be executed is in bfr. */
  224.     if (noshell) {
  225.         if (pid = fork())
  226.             fwait(pid);
  227.         else {
  228.             close(0);
  229.             open(TRANS, 0);
  230.             if (*sp->s_xmit == '\0')
  231.                 ptr = bfr;
  232.             else
  233.                 ptr = sp->s_xmit;
  234.             for (pid = 0; pid < 19; pid++) {
  235.                 while (isspace(*ptr))
  236.                     *ptr++ = 0;
  237.                 argv[pid] = ptr;
  238.                 while (!isspace(*++ptr) && *ptr)
  239.                     ;
  240.                 if (!*ptr)
  241.                     break;
  242.             }
  243.             argv[++pid] = 0;
  244.             execv(argv[0], argv);
  245.             xerror("Can't execv %s", argv[0]);
  246.         }
  247.     } else
  248.         system(bfr);
  249.     if (!appfile && !useexist && !history)    /* 6/18/84 KSA) */
  250.         unlink(TRANS);
  251.     fclose(ifp);
  252.     return TRUE;
  253. }
  254.  
  255. typedef struct {
  256.     char *dptr;
  257.     int dsize;
  258. } datum;
  259.  
  260. /*
  261.  * Return TRUE if we have seen this file before, else FALSE.
  262.  */
  263. history(hp)
  264. struct hbuf *hp;
  265. {
  266. #ifdef DBM
  267.     datum lhs, rhs;
  268.     datum fetch();
  269. #else !DBM
  270.     register FILE *hfp;
  271. #endif !DBM
  272.     register char *p;
  273.     char lcident[BUFLEN];
  274.  
  275. #ifdef DEBUG
  276.     fprintf(stderr,"history(%s)\n", hp->ident);
  277. #endif
  278.     /*
  279.      * Make the article ID case insensitive.
  280.      */
  281.     strcpy(lcident, hp->ident);
  282.     p = lcident;
  283.     while (*++p)
  284.         if (isupper(*p))
  285.             *p = tolower(*p);
  286.  
  287.     idlock(lcident);
  288. #ifdef DBM
  289.     dbminit(ARTFILE);
  290.     lhs.dptr = lcident;
  291.     lhs.dsize = strlen(lhs.dptr) + 1;
  292.     rhs = fetch(lhs);
  293.     if (rhs.dptr)
  294.         return(TRUE);
  295. #else
  296.     hfp = xfopen(ARTFILE, "r");
  297.     while (fgets(bfr, BUFLEN, hfp) != NULL) {
  298.         p = index(bfr, '\t');
  299.         if (p == NULL)
  300.             p = index(bfr, '\n');
  301.         if (p != NULL)    /* can happen if nulls in file */
  302.             *p = 0;
  303.         p = bfr;
  304.         while (*++p)
  305.             if (isupper(*p))
  306.                 *p = tolower(*p);
  307.         
  308.         if (strcmp(bfr, lcident)==0 ||
  309.                 hp->oident[0] && strcmp(bfr, hp->oident)==0) {
  310.             fclose(hfp);
  311.             idunlock();
  312. #ifdef DEBUG
  313.             fprintf(stderr,"history returns true\n");
  314. #endif
  315.             return(TRUE);
  316.         }
  317.     }
  318.     fclose(hfp);
  319. #endif
  320.     addhist(hp->ident);
  321.     addhist("\t");
  322. #ifdef DEBUG
  323.     fprintf(stderr,"history returns false\n");
  324. #endif
  325.     return(FALSE);
  326. }
  327.  
  328. char histline[256];    /* Assumed initially zero */
  329.  
  330. addhist(msg)
  331. char *msg;
  332. {
  333.     strcat(histline, msg);
  334. }
  335.  
  336. savehist(hline)
  337. char *hline;
  338. {
  339.     register FILE *hfp;
  340.     datum lhs, rhs;
  341.     long fpos;
  342.     register char *p;
  343.  
  344.     hfp = xfopen(ARTFILE, "a");
  345.     fpos = ftell(hfp);
  346.     fprintf(hfp, "%s\n", hline);
  347.     fclose(hfp);
  348. #ifdef DBM
  349.     /* We assume that history has already been called, calling dbminit. */
  350.     p = index(hline, '\t');
  351.     if (p)
  352.         *p = 0;
  353.     p = hline;
  354.     while(*++p)
  355.         if(isupper(*p))
  356.             *p = tolower(*p);
  357.     lhs.dptr = hline;
  358.     lhs.dsize = strlen(lhs.dptr) + 1;
  359.     rhs.dptr = (char *) &fpos;
  360.     rhs.dsize = sizeof fpos;
  361.     store(lhs, rhs);
  362. #endif
  363.     hline[0] = 0;
  364.     idunlock();
  365. }
  366.  
  367. /*
  368.  * Save partial news.
  369.  */
  370. newssave(fd, dummy)
  371. FILE *fd;
  372. char *dummy;
  373. {
  374.     register FILE *tofd, *fromfd;
  375.     char sfname[BUFLEN];
  376.     register int c;
  377.     time_t tim;
  378.  
  379. #ifdef lint
  380.     c = *dummy;
  381. #endif lint
  382.  
  383.     if (fd == NULL)
  384.         fromfd = xfopen(INFILE, "r");
  385.     else
  386.         fromfd = fd;
  387.     umask(savmask);
  388.     setgid(gid);
  389.     setuid(uid);
  390.  
  391.     sprintf(sfname, "%s/%s", userhome, PARTIAL);
  392.     if ((tofd = fopen(sfname, "a")) == NULL)
  393.         xerror("Cannot save partial news in %s", sfname);
  394.     time(&tim);
  395.     fprintf(tofd, "----- News saved at %s\n", arpadate(&tim));
  396.     while ((c = getc(fromfd)) != EOF)
  397.         putc(c, tofd);
  398.     fclose(fromfd);
  399.     fclose(tofd);
  400.     printf("News saved in %s\n", sfname);
  401.     xxit(0);
  402. }
  403.  
  404. /*
  405.  * Handle dates in header.
  406.  */
  407.  
  408. dates(hp)
  409. struct hbuf *hp;
  410. {
  411.     time_t edt;
  412.  
  413.     time(&hp->rectime);
  414.     strcpy(hp->recdate, arpadate(&hp->rectime));
  415.     nstrip(hp->recdate);
  416.     if (*hp->subdate) {
  417.         if (cgtdate(hp->subdate) < 0) {
  418.             xerror("Cannot parse submittal date '%s'", hp->subdate);
  419.         }
  420.     } else
  421.         strcpy(hp->subdate, hp->recdate);
  422.     if (*hp->expdate) {
  423.         if ((edt = cgtdate(hp->expdate)) < 0)
  424.             xerror("Cannot parse expiration date '%s'",hp->expdate);
  425.         nstrip(strcpy(hp->expdate, arpadate(&edt)));
  426.     } else {
  427.         defexp = TRUE;
  428.         /*
  429.          * Default is now applied in expire.c
  430.         hp->exptime = hp->rectime + DFLTEXP;
  431.         nstrip(strcpy(hp->expdate, arpadate(&hp->exptime)));
  432.         */
  433.     }
  434. }
  435.  
  436. char lockname[80];
  437. idlock(str)
  438. char *str;
  439. {
  440.     register int i;
  441.     char tempname[80];
  442.     time_t now;
  443.     struct stat sbuf;
  444. #ifdef    VMS
  445.     int fd;
  446.  
  447.     sprintf(lockname, "/tmp/%s.l.1", str);
  448.     if ((fd = creat(lockname, 0444)) < 0) {
  449. #else    !VMS
  450.     sprintf(tempname, "/tmp/LTMP.%d", getpid());
  451.     sprintf(lockname, "/tmp/L%s", str);
  452. #ifdef FOURTEENMAX
  453.     lockname[5 /* /tmp/ */ + 14] = '\0';
  454. #endif
  455.     close(creat(tempname, 0666));
  456.     while (link(tempname, lockname)) {
  457. #endif    !VMS
  458.         (void) time(&now);
  459.         i = stat(lockname, &sbuf);
  460.         if (i < 0) {
  461.             xerror("Directory permission problem in /tmp");
  462.         }
  463.         if (sbuf.st_mtime + 10*60 < now) {
  464.             unlink(lockname);
  465.             logerr("Article %s locked up", str);
  466.             continue;
  467.         }
  468.         log("waiting on lock for %s", lockname);
  469.         sleep((unsigned)60);
  470.     }
  471. #ifdef VMS
  472.     close(fd);
  473. #else
  474.     unlink(tempname);
  475. #endif
  476.     unlink(tempname);
  477. }
  478.  
  479. idunlock()
  480. {
  481.     unlink(lockname);
  482. }
  483.  
  484. /*
  485.  * Put a unique name into header.ident.
  486.  */
  487. getident(hp)
  488. struct hbuf *hp;
  489. {
  490.     long seqn;
  491.     register FILE *fp;
  492.  
  493.     lock();
  494.     fp = xfopen(SEQFILE, "r");
  495.     fgets(bfr, BUFLEN, fp);
  496.     fclose(fp);
  497.     seqn = atol(bfr) + 1;
  498. #ifdef    VMS
  499.     unlink(SEQFILE);
  500. #endif    VMS
  501.     fp = xfopen(SEQFILE, "w");
  502.     fprintf(fp, "%ld\n", seqn);
  503.     fclose(fp);
  504.     unlock();
  505.     sprintf(hp->ident, "<%ld@%s%s>", seqn, FULLSYSNAME, MYDOMAIN);
  506. }
  507.  
  508. /*
  509.  * Check that header.nbuf contains only valid newsgroup names;
  510.  * exit with error if not valid.
  511.  *
  512.  */
  513.  
  514. ngfcheck(isproc)
  515. int isproc;
  516. {
  517.     register char *s1, *s2;
  518.     register FILE *f;
  519.     register char *os1;
  520.     int ngroups = 1;
  521.     char tbuf[BUFLEN], ngcheck[AFSIZ];
  522.  
  523.     f = xfopen(ACTIVE, "r");
  524.     s1 = ngcheck;
  525.     while (fgets(bfr, BUFLEN, f) != NULL) {
  526.         os1 = s1;
  527.         for(s2 = bfr; *s2 != '\0' && *s2 != ' ';) {
  528.             if (s1 >= &ngcheck[AFSIZ-2])
  529.                 xerror("ACTIVE file too long");
  530.             *s1++ = *s2++;
  531.         }
  532.         *s1++ = '\0';
  533.         if (isproc) /* don't check to see if can post to this group */
  534.             continue;    
  535.         while (*s2++ != '\0' && *s2 != ' ')
  536.             ;    /* skip max article number */
  537.         while (*s2++ != '\0' && *s2 != ' ')
  538.             ;    /* skip min article number */
  539.         if (*s2++ != '\0' && *s2 == 'n')
  540.             s1 = os1;    /* can't post to this group */
  541.     }
  542.     *s1++ = '\0';
  543.     *s1 = '\0';
  544.     fclose(f);
  545.         
  546.     s1 = header.nbuf;
  547.     s2 = nbuf;
  548.     while (*s1 == NGDELIM || *s1 == ' ')
  549.         s1++;    /* skip leading junk */
  550.     do {
  551.         /* there shouldn't be blanks, but give the jerk a break */
  552.         if (*s1 == NGDELIM || *s1 == ' ') {
  553.             *s2++ = '\0';
  554.             ngroups++;
  555.             while (*++s1 == NGDELIM || *s1 == ' ')
  556.                 ;    /* remove extra commas */
  557.         } else
  558.             *s2++ = *s1++;
  559.     } while (*s1 != '\0');
  560.     *s2 = '\0';
  561.  
  562.     s1 = nbuf;
  563.     while (*s1 != '\0') {    /* for each newsgroup in header */
  564.         s2 = ngcheck;
  565.         while (*s2 != '\0') { /* for each newsgroup in active file */
  566.             if (strcmp(s1, s2) == 0)
  567.                 break;
  568.             while (*s2++ != '\0')
  569.                 ;
  570.         }
  571.         if (*s2 == '\0') {    /* not found. remove it */
  572.             if (!isproc) {
  573.                 logerr("Invalid news group '%s'", s1);
  574.                 newssave(stdin, (char *)NULL);
  575.             }
  576.             /* See if it's in our alias list */
  577.             f = xfopen(ALIASES,"r");
  578.             while (fscanf(f,"%s %s", tbuf, bfr) == 2
  579.                 && strcmp(s1, tbuf))
  580.                 ;
  581.             fclose(f);
  582.             if (strcmp(s1, tbuf) == 0) {
  583.                 logerr("Aliased newsgroup '%s' to '%s'", s1, bfr);
  584.                 os1 = s1;
  585.                 s1 = nbuf;
  586.                 s2 = tbuf;
  587.                 while (s1 < os1) /* copy left part */
  588.                     *s2++ = *s1++;
  589.                 s1 = bfr;
  590.                 while (*s1 != '\0') /* copy alias */
  591.                     *s2++ = *s1++;
  592.                 *s2++ = '\0';
  593.                 s1 = os1;
  594.                 os1 = nbuf + (s2 - tbuf);
  595.                 while (*s1++ != '\0') /* skip old group */
  596.                     ;
  597.                 /* copy right part */
  598.                 tbufcpy(s2, s1);
  599.                 /* copy back to original buffer */
  600.                 tbufcpy(nbuf, tbuf);
  601.                 s1 = os1;
  602.             } else {
  603.                 logerr("Unknown newsgroup '%s' removed", s1);
  604.                 s2 = s1;
  605.                 while (*s2++ != '\0')    /* skip the bad one */
  606.                     ;
  607.                 tbufcpy(s1, s2);
  608.             }
  609.         } else { /* It's in our active file */
  610.             os1 = s1;
  611.             while (*s1++ != '\0')
  612.                 ;
  613.             /* check for local only distribution on incoming
  614.                newsgroups. This might occur if someone posted to
  615.                general,net.unix */
  616.             if(isproc && ngroups > 1 && index(os1, '.') == NULL) {
  617.                 logerr("Local group '%s' removed", os1);
  618.                 tbufcpy(os1, s1);
  619.                 s1 = os1;
  620.             }
  621.         }
  622.     }
  623.     /*  remove any duplicates */
  624.     os1 = s1 = nbuf;
  625.     for(;;) {
  626.         if (*s1++ == '\0') {
  627.             if (*s1 == '\0')
  628.                 break;
  629.             s2 = s1;
  630.             while (*s2 != '\0') {
  631.                 if (strcmp(os1, s2) == 0) {
  632.                     logerr("Duplicate '%s' removed",os1);
  633.                     os1 = s2;
  634.                     while (*s2++ != '\0') /* skip it */
  635.                         ;
  636.                     tbufcpy(os1, s2);
  637.                 } else
  638.                     while (*s2++ != '\0')
  639.                         ;
  640.             }
  641.             os1 = s1;
  642.             s1[-1] = '\0';
  643.         }
  644.     }
  645.     if (nbuf[0] != '\0') {
  646.         s1 = header.nbuf;
  647.         s2 = nbuf;
  648.         do {
  649.             while (*s2 != '\0')
  650.                 *s1++ = *s2++;
  651.             *s1++ = NGDELIM;
  652.         } while (*++s2 != '\0');
  653.         *s1 = '\0';
  654.         return FALSE;
  655.     }
  656.     return TRUE;
  657. }
  658.  
  659. tbufcpy(s1, s2)
  660. register char *s1, *s2;
  661. {
  662.     do {
  663.         while (*s2 != '\0')
  664.             *s1++ = *s2++;
  665.         *s1++ = '\0';
  666.     } while (*++s2 != '\0');
  667.     *s1 = '\0';
  668. }
  669.  
  670.  
  671. /*
  672.  * Figure out who posted the article (which is locally entered).
  673.  * The results are placed in the header structure hp.
  674.  */
  675. gensender(hp, logname)
  676. struct hbuf *hp;
  677. char *logname;
  678. {
  679.     register char *fn, *p;
  680.     char buf[BUFLEN];
  681.     char *fullname(), *getenv();
  682.     int fd;
  683.  
  684.     fn = getenv("NAME");
  685.  
  686.     if (fn == NULL) {
  687.         sprintf(buf, "%s/%s", userhome, ".name");
  688.         fd = open(buf, 0);
  689.         if (fd >= 0) {
  690.             read(fd, buf, sizeof buf);
  691.             close(fd);
  692.             if (buf[0] >= 'A') {
  693.                 fn = buf;
  694.                 for (p=fn; *p; p++)
  695.                     if (*p < ' ')
  696.                         *p = '\0';
  697.             }
  698.         }
  699.     }
  700.  
  701.     if (fn == NULL)
  702.         fn = fullname(logname);
  703.  
  704.     sprintf(hp->path, "%s", logname);
  705.     sprintf(hp->from, "%s@%s%s (%s)", logname, FULLSYSNAME, MYDOMAIN, fn);
  706. }
  707.  
  708. /*
  709.  * Trap interrupts.
  710.  */
  711. onsig(n)
  712. int n;
  713. {
  714.     static int numsigs = 0;
  715.     /*
  716.      * Most UNIX systems reset caught signals to SIG_DFL.
  717.      * This bad design requires that the trap be set again here.
  718.      * Unfortunately, if the signal recurs before the trap is set,
  719.      * the program will die, possibly leaving the lock in place.
  720.      */
  721.     if (++numsigs > 100) {
  722.         logerr("inews ran away looping on signal %d", n);
  723.         xxit(1);
  724.     }
  725.     signal(n, onsig);
  726.     sigtrap = n;
  727. }
  728.  
  729. #ifdef BATCH
  730. /*
  731.  * If the stdin begins with "#", we assume we have been fed a batched
  732.  * shell script which looks like this:
  733.  *    #! rnews 1234
  734.  *    article with 1234 chars
  735.  *    #! rnews 4321
  736.  *    article with 4321 chars
  737.  *
  738.  * In this case we just exec the unbatcher and let it unpack and call us back.
  739.  *
  740.  * Note that there is a potential security hole here.  If the batcher is
  741.  * /bin/sh, someone could ship you arbitrary stuff to run as shell commands.
  742.  * The main protection you have is that the effective uid will be news, not
  743.  * uucp and not the super user.  (That, plus the fact that BATCH is set to
  744.  * "unbatch" as the system is distributed.)  If you want to run a batched link
  745.  * and you are security concious, do not use /bin/sh as the unbatcher.
  746.  * the thing to do is to change BATCH in your localize.sh file from /bin/sh
  747.  * to some restricted shell which can only run rnews.
  748.  */
  749. checkbatch()
  750. {
  751.     int c;
  752.  
  753.     c = getc(stdin);
  754.     if (c != EOF)
  755.         ungetc(c, stdin);
  756.     clearerr(stdin);
  757.     if (c == '#') {
  758.         char unbatcher[BUFLEN];
  759.  
  760.         sprintf(unbatcher, "%s/%s", LIB, BATCH);
  761.         reset_stdin();
  762.         execl(unbatcher, "news-unpack", (char *)0);
  763.         xerror("Unable to exec shell to unpack news.");
  764.     }
  765. }
  766.  
  767. /*
  768.  * We've already done a read on stdin, and we want to seek back to the
  769.  * beginning.  We want the real file descriptor (beyond buffers) to
  770.  * reflect the true beginning.  Do whatever is necessary.
  771.  */
  772. reset_stdin()
  773. {
  774.     register FILE *ofd;
  775.     register int c;
  776.     char *ofdname;
  777.     long lseek();
  778.  
  779.     /* First try to seek back - if so, it's a cheap way back. */
  780.     if (lseek(0, 0L, 0) == 0L)
  781.         return;
  782.  
  783.     /* Can't seek, so have to copy input to a file and use that. */
  784.     ofdname = "/tmp/inewsXXXXX";
  785.     mktemp(ofdname);
  786.     ofd = fopen(ofdname, "w");
  787.     while ((c=getc(stdin)) != EOF)
  788.         putc(c, ofd);
  789.     fclose(stdin);
  790.     fclose(ofd);
  791.  
  792.     /* Now for a few lower level hacks to reopen stdin and make
  793.      * absolutely sure that the right fd's are done for the exec.
  794.      */
  795.     (void) close(0);        /* make sure stdin is really closed. */
  796.     (void) open(ofdname, 0);    /* should return zero */
  797.     (void) unlink(ofdname);        /* to avoid cleaning it up later. */
  798. }
  799. #endif BATCH
  800.  
  801. /*
  802.  *    Exit and cleanup.
  803.  */
  804. xxit(status)
  805. int status;
  806. {
  807.     unlink(INFILE);
  808.     unlink(ARTICLE);
  809.     while (lockcount > 0)
  810.         unlock();
  811.     idunlock();
  812.     exit(status);
  813. }
  814.  
  815. rwaccess(fname)
  816. char *fname;
  817. {
  818.     int fd;
  819.  
  820.     fd = open(fname, 2);
  821.     if (fd < 0)
  822.         return 0;
  823.     close(fd);
  824.     return 1;
  825. }
  826.  
  827. exists(fname)
  828. char *fname;
  829. {
  830.     int fd;
  831.  
  832.     fd = open(fname, 0);
  833.     if (fd < 0)
  834.         return 0;
  835.     close(fd);
  836.     return 1;
  837. }
  838.  
  839. int    lockcount = 0;            /* no. of times we've called lock */
  840.  
  841. #ifdef    VMS
  842.  
  843. #define    SUBLOCK    "/tmp/netnews.lck.1"
  844.  
  845. /*
  846.  * Newsystem locking.
  847.  * These routines are different for VMS because we can not
  848.  * effectively simulate links, and VMS supports multiple
  849.  * version numbers of files
  850.  */
  851. lock()
  852. {
  853.     register int i;
  854.     register int fd;
  855.  
  856.     if (lockcount++ == 0) {
  857.         i = DEADTIME;
  858.         while ((fd = creat(SUBLOCK, 0444)) < 0) {
  859.             if (--i < 0) {
  860.                 unlink(SUBLOCK);
  861.                 fprintf(stderr,"%s: %s\n", Progname, msg);
  862.                 logerr("News system locked up");
  863.             }
  864.             if (i < -3)
  865.                 xerror("Unable to unlock news system");
  866.             sleep((unsigned)1);
  867.         }
  868.         close(fd);
  869.     }
  870. }
  871.  
  872. unlock()
  873. {
  874.     if (--lockcount == 0)
  875.         unlink(SUBLOCK);
  876. }
  877.  
  878. #else    !VMS
  879.  
  880. /*
  881.  * Newsystem locking.
  882.  */
  883.  
  884. lock()
  885. {
  886.     register int i;
  887.     extern int errno;
  888.  
  889.     if (lockcount++ == 0) {
  890.         i = DEADTIME;
  891.         while (link(SUBFILE, LOCKFILE)) {
  892.             if (errno != EEXIST)
  893.                 break;
  894.             if (--i < 0)
  895.                 xerror("News system locked up");
  896.             sleep((unsigned)1);
  897.         }
  898.     }
  899. }
  900.  
  901. unlock()
  902. {
  903.     if (--lockcount == 0)
  904.         unlink(LOCKFILE);
  905. }
  906. #endif    VMS
  907.  
  908. /*
  909.  * Generate the name of the person responsible for posting this article,
  910.  * in order to check that two articles were posted by the same person.
  911.  */
  912. char *
  913. senderof(hp)
  914. struct hbuf *hp;
  915. {
  916.     char *q, *tp;
  917.     char *tailpath();
  918.  
  919.     if (hp->sender[0])
  920.         tp = hp->sender;
  921.     else if (hp->from[0])
  922.         tp = hp->from;
  923.     else
  924.         tp = tailpath(hp);
  925.  
  926.     /* Remove full name */
  927.     q = index(tp, ' ');
  928.     if (q)
  929.         *q = '\0';
  930.  
  931.     q = malloc((unsigned)(strlen(tp) + 1));
  932.     strcpy(q, tp);
  933.     return q;
  934. }
  935. !E!O!F!
  936.  
  937. cat > lib/addrc.c <<\!E!O!F!
  938. /*
  939.  * Add a newsgroup onto the end of .newsrc.
  940.  */
  941.  
  942. #include <stdio.h>
  943. #include "defs.h"
  944. #include "newsrc.h"
  945.  
  946.  
  947. addrc(ngp)
  948.     struct ngentry *ngp;
  949.     {
  950.     if (lastng != NULL) {
  951.         lastng->ng_next = ngp;
  952.         lastng = ngp;
  953.     } else {
  954.         lastng = firstng = ngp;
  955.     }
  956. }
  957. !E!O!F!
  958.  
  959. cat > lib/af.h <<\!E!O!F!
  960. #include "artfile.h"
  961. #include "stroff.h"
  962.  
  963. /* length of section of artrec that can be written directly to artfile */
  964. #define A_WRTLEN (int)(stroff(a_nkwords, artrec) + 1)
  965.  
  966. /* offsets */
  967. #define PARENTOFF    (stroff(a_parent, artrec) + 1)
  968. #define CHILDRENOFF    (stroff(a_children, artrec) + 1)
  969. #define CHILDCHOFF    (stroff(a_childchain, artrec) + 1)
  970. #define GROUPOFF    (stroff(a_group[0], artrec) + 1)
  971.  
  972.  
  973. #define A_PREFIX 0210        /* this byte precedes each article record */
  974. #define AF_MAGIC 0431        /* magic number to indicate artfile */
  975. #define AF_VERSION 1        /* version number */
  976.  
  977.  
  978. struct afheader {
  979.       short af_magic;        /* magic number (0431) */
  980.       short af_version;        /* version number */
  981.       DPTR  af_idtab;        /* offset of message id hash table */
  982.       DPTR  af_nglist;        /* pointer to newsgroup chain table */
  983.       DPTR  af_titletab;    /* title hash table */
  984.       DPTR  af_records;        /* start of article records */
  985.       DPTR  af_free;        /* add next record here */
  986.       short af_idtlen;        /* # elements in message id hash table */
  987.       short af_maxng;        /* # elements in newsgroup chain table */
  988.       short af_ttlen;        /* # elements in title hash table */
  989. };
  990.  
  991.  
  992. extern struct afheader afhd ;
  993. extern int affd ;
  994.  
  995. #if BUFSIZ == 1024
  996. #define BSIZE 1024
  997. #else
  998. #define BSIZE 512
  999. #endif
  1000.  
  1001.  
  1002. DPTR readptr() ;
  1003.  
  1004. #define ngchain(ngnum)    (afhd.af_nglist + ngnum * (int)sizeof(DPTR))
  1005. #define hashid(msgid)    (afhd.af_idtab + hash(msgid, afhd.af_idtlen) * (int)sizeof(DPTR))
  1006.  
  1007. #define equal(s1, s2)    (strcmp(s1, s2) == 0)
  1008. !E!O!F!
  1009.  
  1010. cat > lib/aflock.c <<\!E!O!F!
  1011. /*
  1012.  * Lock and unlock the article data base.
  1013.  */
  1014.  
  1015. #include <stdio.h>
  1016. #include <errno.h>
  1017. #include "af.h"
  1018. #include <sys/types.h>
  1019. #include <sys/stat.h>
  1020. #include "defs.h"
  1021. #include "libextern.h"
  1022.  
  1023.  
  1024. static int islocked ;
  1025.  
  1026.  
  1027. /*
  1028.  * Lock the data base.  The data base is only locked to avoid multiple
  1029.  * writers, so the data base may be read and written simultaneously.
  1030.  */
  1031.  
  1032. aflock() {
  1033.       char lockfile[FPATHLEN] ;
  1034.       int ntries ;
  1035.       struct stat st ;
  1036.       int fd ;
  1037.       char pid[10] ;
  1038.       long time() ;
  1039.  
  1040.       sprintf(lockfile, "%s/artfile.lck", LIB) ;
  1041.       ntries = 0 ;
  1042.       while (islocked++, (fd = creat(lockfile, 0444)) < 0) {
  1043.             islocked-- ;
  1044.             if (++ntries == 1 || ntries == 31) {
  1045.                   if (stat(lockfile, &st) >= 0 && st.st_mtime < time((long *)0) - 60) {
  1046.                         unlink(lockfile) ;
  1047.                         continue ;
  1048.                   }
  1049.             } else if (ntries > 60) {
  1050.                   xerror("Can't lock data base") ;
  1051.             }
  1052.             sleep(2) ;
  1053.       }
  1054.       sprintf(pid, "%d\n", getpid()) ;
  1055.       write(fd, pid, strlen(pid)) ;
  1056.       close(fd) ;
  1057. #ifdef notdef /* forget about stdio due to BSD bug */
  1058.       fseek(affp, 0L, 0) ;
  1059.       fread((char *)&afhd, sizeof(afhd), 1, affp) ;
  1060. #else
  1061.       lseek(affd, 0L, 0) ;
  1062.       read(affd, (char *)&afhd, sizeof afhd) ;
  1063. #endif
  1064. }
  1065.  
  1066.  
  1067. afunlock() {
  1068.       char lockfile[FPATHLEN] ;
  1069.  
  1070.       if (islocked) {
  1071.             sprintf(lockfile, "%s/artfile.lck", LIB) ;
  1072.             unlink(lockfile) ;
  1073.             islocked-- ;
  1074.       }
  1075. }
  1076. !E!O!F!
  1077.  
  1078. cat > lib/afopen.c <<\!E!O!F!
  1079. #include "defs.h"
  1080. #include "libextern.h"
  1081.  
  1082.  
  1083. afopen() {
  1084.       char fname[FPATHLEN] ;
  1085.  
  1086.       sprintf(fname, "%s/artfile", LIB) ;
  1087.       genafopen(fname, "r") ;
  1088. }
  1089. !E!O!F!
  1090.  
  1091. cat > lib/allgroups.c <<\!E!O!F!
  1092. #include <stdio.h>
  1093. #include "config.h"
  1094. #include "ng.h"
  1095.  
  1096. char *index() ;
  1097.  
  1098.  
  1099. nginit() {
  1100.       int c ;
  1101.  
  1102.       fseek(ngfp, 0L, 0) ;
  1103.       while ((c = getc(ngfp)) != '\n' && c != EOF) ;
  1104. }
  1105.  
  1106.  
  1107. ngread(g)
  1108.       register struct ngrec *g ;
  1109.       {
  1110.       char line[100] ;
  1111.       register char *p ;
  1112.  
  1113.       if (fgets(line, 100, ngfp) == NULL)
  1114.             return 0 ;
  1115.       if ((p = index(line, ' ')) == NULL)
  1116.             xerror("corrupted newsgroup file") ;
  1117.       *p++ = '\0' ;
  1118.       scopyn(line, g->g_name, sizeof(g->g_name)) ;
  1119.       g->g_num = atoi(p) ;
  1120.       g->g_flags = 0 ;
  1121.       if (index(p, 'm'))
  1122.             g->g_flags |= G_MOD ;
  1123.       return 1 ;
  1124. }
  1125. !E!O!F!
  1126.  
  1127. cat > lib/artfile.h <<\!E!O!F!
  1128. /*
  1129.  * Defines for the article data base file
  1130.  */
  1131.  
  1132. /* flags in artrec structure */
  1133. #define A_DUMMY 01        /* placeholder; article not yet arrived */
  1134. #define A_EXPIRED 02        /* article has been expired */
  1135. #define A_CANCELLED 04        /* article has been cancelled */
  1136. #define A_NOFILE 07        /* no file for this article */
  1137.  
  1138.  
  1139. typedef long DPTR ;        /* file address */
  1140. typedef int ARTNO ;        /* article number */
  1141. #define DNULL 0L
  1142.  
  1143.  
  1144. #define MAXNG    5        /* max # newsgroups per article */
  1145. #define A_MAXKW    6        /* max # keywords on an article */
  1146. #define A_SPACE 576        /* space for storing strings */
  1147.  
  1148.  
  1149. struct artgroup {
  1150.       short a_ngnum;        /* number of this newsgroup */
  1151.       long  a_artno;        /* number of article within newsgroup */
  1152.       DPTR  a_ngchain;        /* pointer to previous article in newsgroup */
  1153. };
  1154.  
  1155.  
  1156. struct artrec {
  1157.       long  a_subtime;        /* when article was posted */
  1158.       long  a_rectime;        /* when article was received */
  1159.       long  a_exptime;        /* when this article expires (0 if not specified) */
  1160.       DPTR  a_parent;        /* article this is a followup to */
  1161.       DPTR  a_children;        /* linked list of followups */
  1162.       DPTR  a_childchain;    /* link for followup chain */
  1163.       DPTR  a_idchain;        /* chain for article id hash */
  1164.       DPTR  a_titlechain;    /* title hash chain */
  1165.       short a_flags;        /* various flags */
  1166.       short a_nlines;        /* length of article */
  1167.       char  a_ngroups;        /* number of newsgroups this article posted to */
  1168.       char  a_nkwords;        /* number of keywords on article */
  1169.       struct artgroup a_group[MAXNG];    /* list of groups article posted to */
  1170.       char *a_ident;        /* message id */
  1171.       char *a_title;        /* article subject line */
  1172.       char *a_from;        /* author of article */
  1173.       char *a_file;        /* file containing article */
  1174.       char *a_kword[A_MAXKW];    /* keywords */
  1175.       char  a_space[A_SPACE];    /* space to store strings */
  1176. };
  1177.  
  1178.  
  1179. extern DPTR nglnext ;
  1180.  
  1181. DPTR nglfirst() ;
  1182. ARTNO ngltest() ;
  1183. DPTR lookart() ;
  1184.  
  1185.  
  1186. #define BKWD_GROUP(ngnum, artno, dp, a)    for (dp = nglfirst(ngnum) ; (artno = ngltest(ngnum, &(a))) >= 0 ; dp = nglnext)
  1187.  
  1188. #define ainit(a)
  1189. #define afree(a)
  1190. !E!O!F!
  1191.  
  1192. cat > lib/arthead.h <<\!E!O!F!
  1193. /*
  1194.  * header.h - Article header format
  1195.  */
  1196.  
  1197. #define NUNREC 50
  1198. #define H_SPACE 1024
  1199. #define NHDNAME 24
  1200.  
  1201. /* article header */
  1202. struct    arthead {
  1203.     char    *h_relayversion;    /* Relay-Version:    */
  1204.     char    *h_postversion;        /* Posting-Version:    */
  1205.     char    *h_path;        /* Path:        */
  1206.     char    *h_from;        /* From:        */
  1207.     char    *h_nbuf;        /* Newsgroups:        */
  1208.     char    *h_title;        /* Subject:        */
  1209.     char    *h_ident;        /* Message-ID:        */
  1210.     char    *h_subdate;        /* Date: (submission)    */
  1211.     char    *h_oident;        /* Article-I.D.:    */
  1212.     char    *h_postdate;        /* Posted:        */
  1213.     char    *h_recdate;        /* Date-Received:    */
  1214.     char    *h_expdate;        /* Expires:        */
  1215.     char    *h_references;        /* References:        */
  1216.     char    *h_ctlmsg;        /* Control:        */
  1217.     char    *h_sender;        /* Sender:        */
  1218.     char    *h_replyto;        /* Reply-To:        */
  1219.     char    *h_followto;        /* Followup-To:        */
  1220.     char    *h_distribution;    /* Distribution:    */
  1221.     char    *h_organization;    /* Organization:    */
  1222.     char    *h_numlines;        /* Lines:        */
  1223.     char    *h_keywords;        /* Keywords:        */
  1224.     char    *h_approved;        /* Approved:        */
  1225.     char    *h_summary;        /* Summary:        */
  1226.     char    *h_priority;        /* Priority:        */
  1227.     char    *h_unrec[NUNREC];    /* unrecognized lines    */
  1228.     time_t    h_subtime;        /* subdate in secs    */
  1229.     time_t    h_rectime;        /* recdate in secs    */
  1230.     time_t    h_exptime;        /* expdate in secs    */
  1231.     int    h_intnumlines;        /* Integer version    */
  1232.     int    h_intpriority;        /* Integer version    */
  1233.     char    *h_space[8];        /* string space        */
  1234. };
  1235.  
  1236. #define hset(hdrline)    ((hdrline) != NULL)
  1237.  
  1238. FILE *gethead();
  1239. !E!O!F!
  1240.  
  1241. cat > lib/bcopy.c <<\!E!O!F!
  1242. #include "config.h"
  1243.  
  1244. #if BSDREL < 42
  1245.  
  1246. bcopy(from, to, n)
  1247.       register char *from, *to ;
  1248.       {
  1249.       register int i ;
  1250.  
  1251.       if ((i = n) != 0) {
  1252.             do *to++ = *from++ ;
  1253.             while (--i != 0) ;
  1254.       }
  1255. }
  1256.  
  1257. #endif
  1258. !E!O!F!
  1259.  
  1260. cat > lib/bcopy.pdp <<\!E!O!F!
  1261. / BCOPY(FROM, TO, N)  CHAR *FROM, *TO ;
  1262. /
  1263. /    Copy "n" bytes from "from" to "to".
  1264. /
  1265. .globl    _bcopy
  1266. .globl    csav, cret
  1267.  
  1268. .text
  1269. _bcopy:    jsr  r0, csav        / save registers
  1270.     mov  r5, r4        / get arguments...
  1271.     cmp  (r4)+, (r4)+    /
  1272.     mov  (r4)+, r0        / from
  1273.     mov  (r4)+, r1        / to
  1274.     mov  (r4), r2        / byte count
  1275.     beq  ret        / if zero then return
  1276.     bit  $1, r1        / is "to" odd
  1277.     beq  1f            / yes...
  1278.       movb (r0)+, (r1)+    /   copy one byte to make it even
  1279.       dec  r2        /   and adjust byte count
  1280. 1:    mov  r2, r3        / save (low bit of) count
  1281.     asr  r2            / convert from bytes to words
  1282.     beq  3f            / if any words to copy...
  1283.       bit  $1, r0        /   is "from" even now?
  1284.       beq  2f        /   if not ...
  1285. 1:        movb (r0)+, (r1)+    /     copy bytes...
  1286.         movb (r0)+, (r1)+    /     ...
  1287.         sob  r2, 1b        /     ...
  1288.       br   3f        /   else ...
  1289. 2:        mov  (r0)+, (r1)+    /     copy words...
  1290.         sob  r2, 2b        /     ...
  1291. 3:    ror  r3            / is byte count odd?
  1292.     bcc  ret        / if so...
  1293.        movb (r0)+, (r1)+    /   copy odd byte.
  1294. ret:    jmp  cret        / return
  1295. !E!O!F!
  1296.  
  1297. cat > lib/bcopy.u3b <<\!E!O!F!
  1298.     .file "bcopy.s"        # silly assembler wants this line
  1299.     .globl    bcopy
  1300.     .align    4
  1301. bcopy:    save    &0        # set up stack frame
  1302.     movw    0(%ap), %r0    # get source
  1303.     movw    4(%ap), %r1    # and destination
  1304.     movw    8(%ap), %r2    # get count
  1305.     movblb            # this instruction does it all
  1306.     ret    &0        # return
  1307. !E!O!F!
  1308.  
  1309. cat > lib/bcopy.vax <<\!E!O!F!
  1310. # bcopy (from, to, count) char *from, *to; int count;
  1311. #
  1312. # Copy "count" bytes from "from" to "to"; not guaranteed to
  1313. # work if "from" and "to" overlap.
  1314.  
  1315.     .align    2
  1316.     .globl    _bcopy
  1317. _bcopy:
  1318.     .word    0
  1319.     movl    4(ap), r1        # r1 = from
  1320.     movl    8(ap), r3        # r3 = to
  1321. L1:
  1322.     movzwl    $65535, r0        # while more than 65535 bytes to move
  1323.     cmpl    12(ap), r0
  1324.     jleq    L2            # if <= 65535, break
  1325.     subl2    r0, 12(ap)        # count-=65535 (bytes moved this time)
  1326.     movc3    r0, (r1), (r3)        # r1, r3 magically point to next 65K
  1327.     brb    L1
  1328. L2:
  1329.     movc3    12(ap), (r1), (r3)    # move up to 65535 bytes
  1330.     ret
  1331. !E!O!F!
  1332.  
  1333. cat > lib/bfr.c <<\!E!O!F!
  1334. #include "defs.h"
  1335.  
  1336. char bfr[LBUFLEN];    /* general purpose buffer */
  1337. !E!O!F!
  1338.  
  1339. cat > lib/bzero.c <<\!E!O!F!
  1340. /*
  1341.  * Set nc bytes, starting at cp, to zero.
  1342.  */
  1343.  
  1344. #include "config.h"
  1345.  
  1346. #if BSDREL < 42
  1347.  
  1348. bzero(cp, nc)
  1349. register char    *cp;
  1350. register int    nc;
  1351. {
  1352.     while (--nc >= 0)
  1353.         *cp++ = 0;
  1354. }
  1355.  
  1356. #endif
  1357. !E!O!F!
  1358.  
  1359. cat > lib/bzero.pdp <<\!E!O!F!
  1360. / BZERO(MEM, N)  CHAR *MEM;
  1361. /
  1362. /    Clear "n" bytes of memory starting at "mem".
  1363. /
  1364. .globl    _bzero
  1365. .globl    csav, cret
  1366.  
  1367. .text
  1368. _bzero:    jsr    r0, csav    / save registers
  1369.     mov    4(r5), r0    / get memory pointer...
  1370.     mov    6(r5), r1    / ...and count
  1371.     beq    ret        / return if zero
  1372.     bit    $1, r0        / is address odd?
  1373.     beq    1f        / yes...
  1374.       clrb      (r0)+        /   clear one byte to make it even
  1375.       dec      r1        /   and adjust byte count
  1376. 1:    mov    r1, r3        / save (low bit of) count
  1377.     clr    r2        / get zero into a register and clear carry
  1378.     ror    r1        / convert count to words.
  1379.     asr    r1        / convert count to double words
  1380.     bcc    1f        / if word count was odd
  1381.       mov      r2, (r0)+    /   clear an extra word
  1382.       tst      r1        /   reset condition codes on r1
  1383. 1:    beq    3f        / while r1 ~= 0
  1384. 2:      mov      r2, (r0)+    /   clear a word...
  1385.       mov      r2, (r0)+    /
  1386.       sob      r1, 2b    /   and update count
  1387. 3:    asr    r3        / if count was odd
  1388.     bcc    ret        /
  1389.       movb      r2, (r0)+    /   clear an extra byte
  1390. ret:    jmp    cret        / return
  1391. !E!O!F!
  1392.  
  1393. cat > lib/bzero.u3b <<\!E!O!F!
  1394.     .file    "bzero.u3b"    # assembler wants this
  1395.  
  1396. # This code relies on the fact that bzero(mem, n) is equivalent to
  1397. # strncpy("", mem, n).
  1398.  
  1399.     .globl    bzero
  1400.     .align    4
  1401. bzero:    save    &1        # set up stack frame and save r8
  1402.     movw    0(%ap), %r0    # get address
  1403.     movw    4(%ap), %r1    # and count
  1404.     movw    &0, %r2        # various parameters are zero
  1405.     movaw    zero, %r8    # null string
  1406.     movccep    %r8,%r1,%r0,%r2,%r2    # strncpy insruction
  1407.     ret    &1        # return
  1408.  
  1409.     .data
  1410. zero:    .byte    0
  1411. !E!O!F!
  1412.  
  1413. cat > lib/cancel.c <<\!E!O!F!
  1414. /*
  1415.  * Cancel the article whose header is in hp, by posting a control message
  1416.  * to cancel it.  The scope of the control message depends on who would
  1417.  * really be willing to cancel it.  It is sent as far as it will do any good.
  1418.  * notauthor is true iff the person posting this article is not the
  1419.  * real author of the article being cancelled.
  1420.  */
  1421.  
  1422. #include <stdio.h>
  1423. #include <sys/types.h>
  1424. #include "config.h"
  1425. #include "arthead.h"
  1426. #include "libextern.h"
  1427.  
  1428. cancel(ofp, hp, notauthor)
  1429. FILE *ofp;
  1430. struct arthead *hp;
  1431. int    notauthor;
  1432. {
  1433.     FILE    *inews;
  1434.     char    distgroup[64];
  1435.     int    pid;
  1436.     char    bfr[512];
  1437.     char    *index();
  1438.     FILE    *popen();
  1439.  
  1440.     /* fflush(stdout); */
  1441.     pid = fork();
  1442.     if (pid > 0)
  1443.         return 0;
  1444.     strcpy(distgroup, hp->h_nbuf);
  1445.     if (notauthor)
  1446.         sprintf(distgroup, "to.%s", FULLSYSNAME);
  1447.     else
  1448.         sprintf(distgroup, "%s", hp->h_nbuf);
  1449.     sprintf(bfr, "%s -t 'cmsg cancel %s' -n %s < /dev/null",
  1450.         XINEWS, hp->h_ident, distgroup);
  1451.     if ((inews = popen(bfr, "w")) == NULL)
  1452.         fprintf(ofp, "Can't fork %s\n", XINEWS);
  1453.     else
  1454.         pclose(inews);
  1455.     if (pid == 0)
  1456.         _exit(0);
  1457.     return 0;
  1458. }
  1459. !E!O!F!
  1460.  
  1461. cat > lib/cgtdate.c <<\!E!O!F!
  1462. #include <stdio.h>
  1463. #include <sys/types.h>
  1464. #include "config.h"
  1465. #ifndef BSDREL >= 7
  1466. #include <sys/timeb.h>
  1467. #else
  1468. struct timeb
  1469. {
  1470.     time_t    time;
  1471.     unsigned short millitm;
  1472.     short    timezone;
  1473.     short    dstflag;
  1474. };
  1475. #endif
  1476.  
  1477. time_t getdate();
  1478. long getadate();
  1479.  
  1480.  
  1481. time_t
  1482. cgtdate(datestr)
  1483. char *datestr;
  1484. {
  1485.     time_t    i;
  1486.     char    junk[40],month[40],day[30],time[60],year[50];
  1487.     char    bfr[181];
  1488.  
  1489.     if ((i = getadate(datestr)) != -1L)
  1490.         return i;
  1491.     if ((i = getdate(datestr, (struct timeb *) NULL)) >= 0)
  1492.         return i;
  1493.     sscanf(datestr, "%s %s %s %s %s", junk, month, day, time, year);
  1494.     sprintf(bfr, "%s %s, %s %s", month, day, year, time);
  1495.     return getdate(bfr, (struct timeb *) NULL);
  1496. }
  1497. !E!O!F!
  1498.  
  1499. cat > lib/cgtdatecmd.c <<\!E!O!F!
  1500. /*
  1501.  * This program takes a date as its argument and writes the UN*X internal
  1502.  * value on the standard output.  The primary purpose of this program is
  1503.  * to make it unnecessary to load the cgtdate routine as part of readnews
  1504.  * and/or vnews.
  1505.  */
  1506.  
  1507. #include <stdio.h>
  1508.  
  1509. main(argc, argv)
  1510.       char **argv ;
  1511.       {
  1512.       char buf[1024] ;
  1513.       register int i ;
  1514.       long tim ;
  1515.       long cgtdate() ;
  1516.  
  1517.       buf[0] = '\0' ;
  1518.       for (i = 1 ; i < argc ; i++) {
  1519.             strcat(buf, " ") ;
  1520.             strcat(buf, argv[i]) ;
  1521.       }
  1522.       tim = cgtdate(buf) ;
  1523.       if (tim == -1L)
  1524.             return 1 ;
  1525.       printf("%ld\n", tim) ;
  1526.       return 0 ;
  1527. }
  1528. !E!O!F!
  1529.  
  1530. cat > lib/ckfopen.c <<\!E!O!F!
  1531. /*
  1532.  * Open file, calling xerror on failure.
  1533.  */
  1534.  
  1535. #include <stdio.h>
  1536. #include "config.h"
  1537.  
  1538. FILE *
  1539. ckfopen(name, mode)
  1540. register char *name, *mode;
  1541. {
  1542.     register FILE *fp;
  1543.     extern int errno;
  1544.  
  1545.     if ((fp = fopen(name, mode)) == NULL) {
  1546. #ifdef IHCC
  1547.         char    *fname, *rindex();
  1548.         /*
  1549.          * IHCC users only see the "filename" that was in trouble,
  1550.          * not the whole path.  (for security!)
  1551.          */
  1552.         if ((fname = rindex(name, '/') != NULL)
  1553.             fname++;
  1554.         else
  1555.             fname = name;
  1556.         xerror("Cannot open %s (%s), errno=%d", fname, mode, errno);
  1557. #else
  1558.         xerror("Cannot open %s (%s), errno=%d", name, mode, errno);
  1559. #endif
  1560.     }
  1561. #ifdef notdef /* this doesn't make sense for readnews */
  1562.     /* kludge for setuid not being honored for root */
  1563.     if ((uid == 0) && (duid != 0) && ((mode == "a") || (mode == "w")))
  1564.         chown(name, duid, dgid);
  1565. #endif
  1566.     return(fp);
  1567. }
  1568. !E!O!F!
  1569.  
  1570. cat > lib/ckmalloc.c <<\!E!O!F!
  1571. char *
  1572. ckmalloc(nbytes)
  1573.       unsigned nbytes ;
  1574.       {
  1575.       register char *p ;
  1576.       char *malloc() ;
  1577.  
  1578.       if ((p = malloc(nbytes)) == (char *)0)
  1579.             xerror("out of space") ;
  1580.       return p ;
  1581. }
  1582. !E!O!F!
  1583.  
  1584. cat > lib/config.hou3c <<\!E!O!F!
  1585. # This is the config file I use on hou3c.
  1586.  
  1587. newsusr netnews
  1588. newsgrp other
  1589. myorg    AT&T Bell Labs, Holmdel
  1590. mydomain .UUCP
  1591. path    /bin:/usr/bin:/usr/lbin
  1592. spool    /tools/netnews/spool
  1593. admin ka
  1594. notify
  1595. admsub
  1596. !E!O!F!
  1597.  
  1598. cat > lib/config.sample <<\!E!O!F!
  1599. #This is a sample config file (with more comments than a real config file
  1600. #would contain, of course).  First, we list all the possible entries.
  1601. #
  1602. #Lines in the setup file consist of a name followed by a value.  The various
  1603. #types of values are string, indicated by "str", integer, indicated by "int",
  1604. #and boolean, indicated by "bool".  The default value, if any, is indicated
  1605. #by DFT.  In certain cases, there is a default which is assigned when a null
  1606. #value is given for the value.  If the value is boolean, the default is "yes",
  1607. #other defaults for null values are indicated by NDFT.
  1608. #
  1609. #
  1610. #NAME       TYPE    DESCRTIPTION
  1611. #admin       str    Netnews administrator.  (DFT is your login name)
  1612. #admsub       str    Mandatory subscription list.  DFT general,all.announce
  1613. #bin       str    Directory where programs (e. g. inews) placed.  DFT /usr/bin
  1614. #buflen       int    Length of various bufs.  DFT 128 if small, else 256
  1615. #compadmin bool    Recompute the numeric admin id each time program run.  DFT no
  1616. #datelen   int    Max length of date.  DFT 48
  1617. #dfteditor str    Default editor program.  DFT /bin/ed
  1618. #dftexp    int    Default expiration time in days.  DFT 14
  1619. #dftsub       str    Default subscription list.  DFT all
  1620. #fpathlen  int    Max length of file path name.  DFT 64
  1621. #ghname       bool    True if system has gethostname call.  DFT yes if 4.2bsd.
  1622. #home       str    Lib and spool are relative to this user's home directory.
  1623. #internet  bool True if mailer understands internet addresses.  DFT yes
  1624. #lbuflen   int    Length of large buffer.  DFT 1024
  1625. #lib       str    Directory for misc netnews files.  DFT /usr/lib/news
  1626. #mailer       str    Mail program.  DFT /bin/mail
  1627. #manually  bool    Require that admin remove groups manually.  DFT yes
  1628. #maxgroups int    Maximum number of newsgroups.
  1629. #mydomain  str    Appended to sys name to get domain name.  This entry mandatory.
  1630. #myname       str    System name.  Computed at run time if omitted.
  1631. #myorg       str    Organization name.  This entry mandatory.
  1632. #namelen   int    Max length of internet address or messge ID.  DFT 64
  1633. #newsgrp   str    Group of news software.  This entry is mandatory.
  1634. #newsrc       str    Name of newsrc file.  DFT .newsrc
  1635. #newsusr   str    Owner of news software.  This entry is mandatory.
  1636. #notify       str    Inform person about certain control messages.  NDFT admin
  1637. #page       str    Pager program.  NDFT /usr/ucb/more
  1638. #path       str    Path use by setup to find various programs.  DFT $PATH
  1639. #pathlen   int    Max length of return path.  DFT 512
  1640. #small       bool    True if 16 bit address space.  DFT yes if on pdp11.
  1641. #spool       str    Directory where articles stored.  DFT /usr/spool/news
  1642. #sys       str    Operating system version.  (Guessed by default)
  1643. #termcap   str    Name of termcap library.  (Guessed by default)
  1644. #tmail       str    Mailer that understands -t option.  NDFT /usr/lib/sendmail
  1645. #umask       int    Umask value; use 022 for secure system.  DFT 000
  1646. #uname       bool    True if system has uname system call.  DFT yes if USG system.
  1647. #v7mail       bool    True if use Version 7 mail format.  DFT yes
  1648.  
  1649.  
  1650. # OK, now to give our config entries.
  1651. # First we give the required ones.
  1652.  
  1653. # The login and group owning the netnews software.
  1654. newsusr netnews
  1655. newsgrp other
  1656.  
  1657. # The name of my organization.
  1658. myorg    AT&T Bell Labs, Holmdel
  1659.  
  1660. # My domain.
  1661. mydomain .UUCP
  1662.  
  1663. # The remaining entries are not required by the setup program.
  1664.  
  1665. # Use a standard path for the rest of setup
  1666. path    /bin:/usr/bin:/usr/lbin
  1667.  
  1668. # We don't have room in the /usr file system for the spool directory,
  1669. # so we place it elsewhere.
  1670. spool /tools/netnews/spool
  1671.  
  1672. # Since I am running the setup program, this is unnecessary, but it is
  1673. # safer to include it in case somebody else recompiles the news software
  1674. # for some reason
  1675. admin ka
  1676.  
  1677. # I want to be told about create and rmgrp control messages.  Since I am
  1678. # the person running the config program, they will be sent to me by default.
  1679. notify
  1680.  
  1681. # Mandatory subscripts are fascist, so no mandatory subscriptions on hou3c.
  1682. admsub
  1683.  
  1684. # End of sample config file.
  1685. !E!O!F!
  1686.  
  1687. cat > lib/cpu.c <<\!E!O!F!
  1688. /* This file is run through cpp to determine the cpu type */
  1689. #ifdef pdp11
  1690. Xpdp11
  1691. #endif
  1692. #ifdef vax
  1693. Xvax
  1694. #endif
  1695. #ifdef u3b
  1696. Xu3b
  1697. #endif
  1698. !E!O!F!
  1699.  
  1700. cat > lib/defs.h <<\!E!O!F!
  1701. /*
  1702.  * defs.h - defines for news-related programs.
  1703.  *
  1704.  * By convention, the version of the software you are running is taken
  1705.  * to be news_version below.
  1706.  */
  1707.  
  1708. #define news_version "B 2.11-B 1/17/84"
  1709. /* SCCS ID @(#)defs.dist    2.23    5/3/83 */
  1710.  
  1711. #include "newsdefs.h"    /* this gets most of the definitions */
  1712.  
  1713. #define FOLLOWUP INEWS
  1714. #define NEWSRC    ".newsrc"
  1715. /* #define BERKNAME "ARPAVAX"    /* name of local host on Berknet    */
  1716.  
  1717. #define LINES    512    /* maximum no. of lines in .newsrc        */
  1718. #define NEGCHAR    '!'    /* newsgroup negation character            */
  1719. #define DEADTIME 45    /* no. of seconds to wait on deadlock        */
  1720. #define FMETA    '%'    /* file meta-character for c option        */
  1721. #define SYSPATH    "PATH=/local/bin:/bin:/usr/bin"    /* default, secure, vanilla path */
  1722. #define LNCNT    16    /* Articles with > LNCNT lines go through pager */
  1723.  
  1724. /* Things you probably won't want to change */
  1725. #define    SNLN    8    /* max significant characters in sysname    */
  1726. #define    PROTO    'A'    /* old protocol name                */
  1727. #define NETCHRS    "!:.@^%"/* Punct. chars used for various networks    */
  1728. #define    TRUE    1    /* boolean true                    */
  1729. #define    FALSE    0    /* boolean false                */
  1730. #define NGFSIZ  5000    /* legal newsgroup file size            */
  1731. #define    NGDELIM    ','    /* delimit character in news group line        */
  1732. !E!O!F!
  1733.  
  1734. cat > lib/dir.c <<\!E!O!F!
  1735. #include "config.h"
  1736. #if BSDREL < 42
  1737. #include <sys/types.h>
  1738. #include <sys/param.h>
  1739. #include "ndir.h"
  1740.  
  1741. /*
  1742.  * open a directory.
  1743.  */
  1744. DIR *
  1745. opendir(name)
  1746.     char *name;
  1747. {
  1748.     register DIR *dirp;
  1749.     register int fd;
  1750.     char *malloc();
  1751.  
  1752.     if ((fd = open(name, 0)) == -1)
  1753.         return NULL;
  1754.     if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
  1755.         close (fd);
  1756.         return NULL;
  1757.     }
  1758.     dirp->dd_fd = fd;
  1759.     dirp->dd_nleft = 0;
  1760.     return dirp;
  1761. }
  1762.  
  1763.  
  1764.  
  1765. /*
  1766.  * close a directory.
  1767.  */
  1768. void
  1769. closedir(dirp)
  1770.     register DIR *dirp;
  1771. {
  1772.     close(dirp->dd_fd);
  1773.     free(dirp);
  1774. }
  1775.  
  1776.  
  1777.  
  1778. /*
  1779.  * read an old style directory entry and present it as a new one
  1780.  */
  1781. #define    ODIRSIZ    14
  1782.  
  1783. struct    olddirect {
  1784.     ino_t    od_ino;
  1785.     char    od_name[ODIRSIZ];
  1786. };
  1787.  
  1788. /*
  1789.  * get next entry in a directory.
  1790.  */
  1791. struct direct *
  1792. readdir(dirp)
  1793.     register DIR *dirp;
  1794. {
  1795.     register struct olddirect *dp;
  1796.     static struct direct dir;
  1797.  
  1798.     for (;;) {
  1799.         if ((dirp->dd_nleft -= sizeof(struct olddirect)) < 0) {
  1800.             dirp->dd_nleft = read(dirp->dd_fd, dirp->dd_buf, 
  1801.                 DIRBLKSIZ);
  1802.             if (dirp->dd_nleft <= 0)
  1803.                 return NULL;
  1804.             dirp->dd_nextc = dirp->dd_buf;
  1805.         }
  1806.         dp = (struct olddirect *) dirp->dd_nextc;
  1807.         dirp->dd_nextc += sizeof(struct olddirect);
  1808.         if (dp->od_ino == 0)
  1809.             continue;
  1810.         dir.d_ino = dp->od_ino;
  1811.         strncpy(dir.d_name, dp->od_name, ODIRSIZ + 1);
  1812.         dir.d_namlen = strlen(dir.d_name);
  1813.         return (&dir);
  1814.     }
  1815. }
  1816. #endif
  1817. !E!O!F!
  1818.  
  1819. cat > lib/dirname.c <<\!E!O!F!
  1820. #include "defs.h"
  1821. #include "libextern.h"
  1822.  
  1823.  
  1824. char *
  1825. dirname(ngname, rbuf)
  1826. char *ngname;
  1827. char rbuf[FPATHLEN];
  1828. {
  1829.     register char *p;
  1830.  
  1831.     sprintf(rbuf, "%s/%s", SPOOL, ngname);
  1832.     for (p=rbuf+strlen(SPOOL); *p; p++)
  1833.         if (*p == '.')
  1834.             *p = '/';
  1835.     return rbuf;
  1836. }
  1837. !E!O!F!
  1838.  
  1839. cat > lib/doc.h <<\!E!O!F!
  1840. .na
  1841. Newsgroups may be refered to by name or my number.
  1842. The name is identical across all machines,
  1843. the number is specific to a particular machine.
  1844.  
  1845. Articles are refered to by message id, by number in newsgroup,
  1846. or by offset into data base.
  1847. The message id is the same on all machines.
  1848. The number is specific to a given machine.
  1849. The offset into the data base is specific to a particular
  1850. machine and a particular open call to the data base.
  1851. (When expire runs, it moves the article records.
  1852. A program which has the data base open will continue
  1853. to use the old data base, however, so that the same offsets
  1854. will still work.)
  1855.  
  1856. The article data base contains a record for each article.
  1857. It consists of a single file divided into several sections.
  1858. First is the header, which gives the size of the other sections.
  1859. Second is a hash table for message ids.
  1860. Third is a hash table of reference lines which is used to deal with
  1861. orphaned articles.
  1862. Fourth is a table of pointers to newsgroup chains.
  1863. All the articles in a newsgroup are connected by a singly linked list.
  1864. Finally, the article records appear.
  1865.  
  1866. There is one article record for each article.
  1867. !E!O!F!
  1868.  
  1869. cat > lib/findgroup.c <<\!E!O!F!
  1870. #include "defs.h"
  1871. #include "str.h"
  1872. #include "newsrc.h"
  1873.  
  1874.  
  1875. struct ngentry *
  1876. findgroup(name)
  1877.       register char *name ;
  1878.       {
  1879.       register struct ngentry *ngp ;
  1880.       extern int maxng ;
  1881.  
  1882.       for (ngp = ngtable; ngp < ngtable + MAXGROUPS ; ngp++) {
  1883.             if (ngp->ng_name && equal(ngp->ng_name, name))
  1884.                   return ngp ;
  1885.       }
  1886.       return 0 ;
  1887. }
  1888. !E!O!F!
  1889.  
  1890. cat > lib/ftime.c <<\!E!O!F!
  1891. #include "config.h"
  1892.  
  1893. #if BSDREL < 7
  1894. static char *SccsId = "@(#)ftime.c    2.3    3/3/83";
  1895.  
  1896. #include <sys/types.h>
  1897. struct timeb
  1898. {
  1899.     time_t    time;
  1900.     unsigned short millitm;
  1901.     short    timezone;
  1902.     short    dstflag;
  1903. };
  1904.  
  1905. extern long timezone;
  1906. extern int  daylight;
  1907.  
  1908. ftime(tp)
  1909. struct timeb *tp;
  1910. {
  1911.     long t;
  1912.  
  1913.     tzset();        /* be sure time zone info set */
  1914.     time(&t);
  1915.     tp->time = t;
  1916.     tp->millitm = 0;
  1917.     tp->timezone = timezone/60;
  1918.     tp->dstflag = daylight;
  1919. }
  1920. #endif
  1921. !E!O!F!
  1922.  
  1923. cat > lib/genafopen.c <<\!E!O!F!
  1924. #include <stdio.h>
  1925. #include "af.h"
  1926.  
  1927.  
  1928. int affd ;            /* artfile file descriptor */
  1929. struct afheader afhd ;        /* artfile header */
  1930.  
  1931.  
  1932. genafopen(file, mode)
  1933.       char *file, *mode ;
  1934.       {
  1935.       int omode = mode[1] ? 2 : 0 ;
  1936.  
  1937.       if ((affd = open(file, omode)) < 0
  1938.        && (sleep(2), affd = open(file, omode)) < 0)
  1939.             xerror("can't open %s", file) ;
  1940.       if (read(affd, (char *)&afhd, sizeof(afhd)) != sizeof afhd)
  1941.             xerror("can't read data base header") ;
  1942.       if (afhd.af_magic != AF_MAGIC)
  1943.             xerror("bad data base file") ;
  1944.       if (afhd.af_version != AF_VERSION)
  1945.             xerror("Version of article data base is wrong") ;
  1946. }
  1947. !E!O!F!
  1948.  
  1949. cat > lib/genmakefile <<\!E!O!F!
  1950. . makedefs
  1951. exec > makefile
  1952. cat <<\!
  1953. # makefile for rlib    1/4/85
  1954.  
  1955. !
  1956. cat makedefs
  1957. cat <<\!
  1958.  
  1959. CFLAGS = $(DEBUG)
  1960. DEBUG = -O
  1961. MAKE = make
  1962.  
  1963. RLIB = aflock.o afopen.o cancel.o cgtdate.o dir.o dirname.o\
  1964. genafopen.o getadate.o getdate.o ftime.o gethead.o getopt.o\
  1965. getuser.o hfgets.o hfree.o hxchg.o isadmin.o isre.o launder.o\
  1966. lookup.o ngchain.o ngmatch.o openrc.o pgetuser.o read.o\
  1967. replyname.o rewinddir.o rmnf.o readinrc.o roptions.o titmat.o\
  1968. write.o setupgrp.o addrc.o allgroups.o findgroup.o gfopen.o\
  1969. makehimask.o nextgrp.o prevgrp.o bfr.o bcopy.o bzero.o ckfopen.o\
  1970. getaddr.o hash.o lcase.o nsavestr.o nstrip.o prefix.o process.o\
  1971. rename.o savestr.o ckmalloc.o scopyn.o strpbrk.o strcspn.o\
  1972. strspn.o strtok.o tomsgid.o
  1973.  
  1974.  
  1975. all: setuptime makefile rlib.a cgtdate rpathinit.o newer
  1976.  
  1977. install: all
  1978.     /bin/cp cgtdate $(LIBDIR)/cgtdate
  1979.  
  1980. setuptime: setup config
  1981.     sh setup
  1982.  
  1983. makefile: genmakefile makedefs
  1984.     genmakefile    
  1985.     @echo 'Makefile changed.  Restart make program.'
  1986.     @sh -c 'exit 22'
  1987.  
  1988. rlib.a: $(RLIB)
  1989.     rm -f $@
  1990.     ar rc $@ $(RLIB)
  1991. !
  1992. if test $BSDREL -gt 7
  1993. then    echo "    ranlib \$@"
  1994. fi
  1995. : Add more assembly language routines when they have been tested.
  1996. case $CPU in
  1997. pdp11)    files="" suffix=pdp ;;
  1998. vax)    files="scopyn" suffix=vax ;;
  1999. u3b)    files="bcopy bzero scopyn strpbrk" suffix=u3b ;;
  2000. *)    files=
  2001. esac
  2002. for x in $files
  2003. do    cat <<!
  2004.  
  2005. $x.o: $x.$suffix
  2006.     \$(AS) -o $x.o $x.$suffix
  2007. !
  2008. done
  2009. cat <<\!
  2010.  
  2011. rpathinit.o: mypathinit.c defs.h newsdefs.h $(FRC)
  2012.     $(CC) -c $(CFLAGS) mypathinit.c
  2013.     mv mypathinit.o rpathinit.o
  2014.  
  2015. genafopen.o lock.o lookup.o ngchain.o read.o: af.h artfile.h
  2016. readinrc.o setupgrp.o: artfile.h
  2017. addrc.o nextgrp.o prevgrp.o readinrc.o setupgrp.o: newsrc.h
  2018. allgroups.o readinrc.o: ng.h
  2019. cancel.o gethead.o hfree.o hxchg.o: arthead.h
  2020. $(RLIB): $(FRC)
  2021.  
  2022. cgtdate: cgtdatecmd.o cgtdate.o getadate.o getdate.o
  2023.     $(CC) $(LFLAGS) -o $@ cgtdatecmd.o rlib.a
  2024.  
  2025. newer: newer.c
  2026.     $(CC) -o $@ newer.c
  2027.  
  2028. FRC:
  2029. !
  2030. !E!O!F!
  2031. chmod +x lib/genmakefile
  2032.  
  2033. cat > lib/getadate.c <<\!E!O!F!
  2034. /*
  2035.  * getadate - get arpa date.
  2036.  *
  2037.  * This routine takes a character character string containing a
  2038.  * date-time in the format specified in RFC 822 and converts it
  2039.  * to UNIX internal format.  The components of the date are left
  2040.  * in the global tm structure arpadtm.  Getarpad returns -1L if
  2041.  * the argument is syntactically incorrect.
  2042.  */
  2043.  
  2044. #include "config.h"
  2045. #if BSDREL == 42
  2046. #include <sys/time.h>
  2047. #else
  2048. #include <time.h>
  2049. #endif
  2050. #include <ctype.h>
  2051.  
  2052. #define HR 3600
  2053. #define DAY (24L*HR)
  2054.  
  2055. struct tm adatetm ;
  2056.  
  2057. static int lookup(), getdig(), skipbl() ;
  2058. static char *d ;
  2059. static char *days[] = {"sun", "mon", "tue", "wed", "thu", "fri", "sat", 0} ;
  2060. static char *months[] = {"jan", "feb", "mar", "apr", "may", "jun",
  2061.              "jul", "aug", "sep", "oct", "nov", "dec", 0} ;
  2062. static char *zones[] =
  2063.        {"ut", "gmt", "est", "edt", "cst", "cdt", "mst", "mdt", "pst", "pdt",
  2064.     "a", "b", "c", "d", "e", "f", "g", "h", "i", "k", "l", "m",
  2065.     "n",   "o",   "p",   "q",   "r",   "s",
  2066.     "t",   "u",   "v",   "w",   "x",   "y",  "z",
  2067.     /* the remaining time zones are not legal according to RFC822 */
  2068.     "yst", "ydt", "hst", "hdt",
  2069.     "aest", "aesst", "acst",    "acsst",    "awst", 0} ;
  2070. static long zoffset[] =
  2071.        {0,    0,      5*HR,  4*HR,  6*HR,  5*HR,  7*HR,  6*HR,  8*HR,  7*HR,
  2072.     1*HR,2*HR,3*HR,4*HR,5*HR,6*HR,7*HR,8*HR,9*HR,10*HR,11*HR,12*HR,
  2073.     -1*HR, -2*HR, -3*HR, -4*HR, -5*HR, -6*HR,
  2074.     -7*HR, -8*HR, -9*HR,-10*HR,-11*HR,-12*HR, 0,
  2075.     /* the remaining time zones are not legal according to RFC822 */
  2076.     9*HR,  8*HR,  10*HR, 9*HR,
  2077.     -10*HR, -11*HR,  -9*HR-HR/2,-10*HR-HR/2,-8*HR,  0} ;
  2078. static int mon[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334} ;
  2079.  
  2080.  
  2081. long
  2082. getadate(date)
  2083.       register char *date ;
  2084.       {
  2085.       int i ;
  2086.       int oh ;
  2087.       long tim ;
  2088.       long offset ;
  2089.  
  2090.       d = date ;
  2091.       if ((adatetm.tm_wday = lookup(days)) >= 0) {
  2092.             if (getch(',') < 0)
  2093. bad:              return -1L ;
  2094.       }
  2095.       skipbl() ;
  2096.       if (! isdigit(*d))
  2097.             goto bad ;
  2098.       adatetm.tm_mday = *d++ - '0' ;
  2099.       if (isdigit(*d))
  2100.             adatetm.tm_mday = adatetm.tm_mday * 10 + *d++ - '0' ;
  2101.       if (*d == '-')        /* ARPA spec doesn't permit this */
  2102.             d++ ;
  2103.       if ((adatetm.tm_mon = lookup(months)) < 0)
  2104.             goto bad ;
  2105.       getch('-') ;        /* ARPA spec doesn't permit this */
  2106.       if ((adatetm.tm_year = getdig()) < 0)
  2107.             goto bad ;
  2108.       skipbl() ;
  2109.       if ((adatetm.tm_hour = getdig()) < 0)
  2110.             goto bad ;
  2111.       if (getch(':') < 0)
  2112.             goto bad ;
  2113.       if ((adatetm.tm_min = getdig()) < 0)
  2114.             goto bad ;
  2115.       if (getch(':') < 0)
  2116.             adatetm.tm_sec = 0 ;
  2117.       else if ((adatetm.tm_sec = getdig()) < 0)
  2118.             goto bad ;
  2119.       if (getch('+') >= 0) {
  2120.             offset = 60 ;
  2121. numtz:      if ((oh = getdig()) < 0
  2122.              || (i = getdig()) < 0)
  2123.                   goto bad ;
  2124.             offset *= 60 * oh + i ;
  2125.       } else if (getch('-') >= 0) {
  2126.             offset = -60 ;
  2127.             goto numtz ;
  2128.       } else if ((i = lookup(zones)) >= 0)
  2129.             offset = zoffset[i] ;
  2130.       else
  2131.             goto bad ;
  2132.  
  2133.       /* now calculate the time */
  2134.       adatetm.tm_yday = mon[adatetm.tm_mon] + adatetm.tm_mday - 1 ;
  2135.       if ((adatetm.tm_year & 03) == 0 && adatetm.tm_mon >= 2)
  2136.             adatetm.tm_yday++ ;
  2137.       tim = adatetm.tm_sec + 60 * adatetm.tm_min + 3600L * adatetm.tm_hour
  2138.           + offset + DAY * adatetm.tm_yday ;
  2139.       for (i = adatetm.tm_year ; --i >= 70 ; )
  2140.             tim += (i & 03) == 0?  366 * DAY : 365 * DAY ;
  2141.       return tim ;
  2142. }
  2143.  
  2144.  
  2145.  
  2146. static int
  2147. lookup(ltab)
  2148.       char **ltab ;
  2149.       {
  2150.       char tok[20] ;
  2151.       register char *dp ;
  2152.       register char *tp ;
  2153.       register char **lp ;
  2154.  
  2155.       dp = d ;
  2156.       tp = tok ;
  2157.       while (isspace(*dp))
  2158.             dp++ ;
  2159.       for (;;) {
  2160.             if (isupper(*dp))
  2161.                   *tp++ = tolower(*dp) ;
  2162.             else if (islower(*dp))
  2163.                   *tp++ = *dp ;
  2164.             else
  2165.                   break ;
  2166.             if (tp >= &tok[20])
  2167.                   return -1 ;
  2168.             dp++ ;
  2169.       }
  2170.       if (dp == d)
  2171.             return -1 ;
  2172.       *tp = '\0' ;
  2173.       for (lp = ltab ; *lp ; lp++) {
  2174.             if (strcmp(*lp, tok) == 0) {
  2175.                   d = dp ;
  2176.                   return lp - ltab ;
  2177.             }
  2178.       }
  2179.       return -1 ;
  2180. }
  2181.  
  2182.  
  2183. static int
  2184. getdig() {
  2185.       register char *p ;
  2186.  
  2187.       p = d ;
  2188.       if (! isdigit(*p) || ! isdigit(*++p))
  2189.             return -1 ;
  2190.       d += 2 ;
  2191.       return 10 * p[-1] + p[0] - (10 * '0' + '0') ;
  2192. }
  2193.  
  2194.  
  2195. static
  2196. skipbl() {
  2197.       while (isspace(*d))
  2198.             d++ ;
  2199. }
  2200.  
  2201.  
  2202. static int
  2203. getch(c) {
  2204.       skipbl() ;
  2205.       if (*d != c)
  2206.             return -1 ;
  2207.       d++ ;
  2208.       skipbl() ;
  2209.       return 0 ;
  2210. }
  2211. !E!O!F!
  2212.  
  2213. cat > lib/getaddr.c <<\!E!O!F!
  2214. /*
  2215.  * Get the machine address of a person, stripping off the real name.
  2216.  */
  2217.  
  2218. #include <stdio.h>
  2219. #include "config.h"
  2220. #include "defs.h"
  2221.  
  2222. char *
  2223. getaddr(full, mach)
  2224.       char full[] ;
  2225.       char mach[NAMELEN] ;
  2226.       {
  2227.       register char *p, *q, *r ;
  2228.       char *index(), *rindex();
  2229.  
  2230.       p = full ;
  2231.       if ((q = index(p, '(')) == NULL)
  2232.             q = p + strlen(p) ;
  2233.       if ((p = index(full, '<')) != NULL && p < q && (r = rindex(p, '>')) != NULL) {
  2234.             p++ ;
  2235.             q = r ;
  2236.       } else
  2237.             p = full ;
  2238.       while (*p == ' ')
  2239.             p++ ;
  2240.       while (--q > p && *q == ' ') ;
  2241.       if (q > p + NAMELEN - 1)
  2242.             q = p + NAMELEN - 1 ;
  2243.       r = mach ;
  2244.       while (p <= q)
  2245.             *r++ = *p++ ;
  2246.       *r = '\0' ;
  2247.       return mach ;
  2248. }
  2249. !E!O!F!
  2250.  
  2251. cat > lib/getdate.y <<\!E!O!F!
  2252. %token ID MONTH DAY MERIDIAN NUMBER UNIT MUNIT SUNIT ZONE DAYZONE AGO
  2253. %{
  2254.     /*     Steven M. Bellovin (unc!smb)            */
  2255.     /*    Dept. of Computer Science            */
  2256.     /*    University of North Carolina at Chapel Hill    */
  2257.     /*    @(#)getdate.y    2.6    4/20/84    */
  2258.  
  2259. #include <sys/types.h>
  2260. #include "config.h"
  2261. #if BSDREL < 7
  2262. struct timeb
  2263. {
  2264.     time_t    time;
  2265.     unsigned short millitm;
  2266.     short    timezone;
  2267.     short    dstflag;
  2268. };
  2269. #else
  2270. #include <sys/timeb.h>
  2271. #endif
  2272. #include <ctype.h>
  2273. #include <time.h>
  2274.  
  2275. #define    NULL    0
  2276. #define daysec (24L*60L*60L)
  2277.     static int timeflag, zoneflag, dateflag, dayflag, relflag;
  2278.     static time_t relsec, relmonth;
  2279.     static int hh, mm, ss, merid, daylight;
  2280.     static int dayord, dayreq;
  2281.     static int month, day, year;
  2282.     static int ourzone;
  2283. #define AM 1
  2284. #define PM 2
  2285. #define DAYLIGHT 1
  2286. #define STANDARD 2
  2287. #define MAYBE    3
  2288. %}
  2289.  
  2290. %%
  2291. timedate:         /* empty */
  2292.     | timedate item;
  2293.  
  2294. item:    tspec =
  2295.         {timeflag++;}
  2296.     | zone =
  2297.         {zoneflag++;}
  2298.     | dtspec =
  2299.         {dateflag++;}
  2300.     | dyspec =
  2301.         {dayflag++;}
  2302.     | rspec =
  2303.         {relflag++;}
  2304.     | nspec;
  2305.  
  2306. nspec:    NUMBER =
  2307.         {if (timeflag && dateflag && !relflag) year = $1;
  2308.         else {timeflag++;hh = $1/100;mm = $1%100;ss = 0;merid = 24;}};
  2309.  
  2310. tspec:    NUMBER MERIDIAN =
  2311.         {hh = $1; mm = 0; ss = 0; merid = $2;}
  2312.     | NUMBER ':' NUMBER =
  2313.         {hh = $1; mm = $3; merid = 24;}
  2314.     | NUMBER ':' NUMBER MERIDIAN =
  2315.         {hh = $1; mm = $3; merid = $4;}
  2316.     | NUMBER ':' NUMBER ':' NUMBER =
  2317.         {hh = $1; mm = $3; ss = $5; merid = 24;}
  2318.     | NUMBER ':' NUMBER ':' NUMBER MERIDIAN =
  2319.         {hh = $1; mm = $3; ss = $5; merid = $6;};
  2320.  
  2321. zone:    ZONE =
  2322.         {ourzone = $1; daylight = STANDARD;}
  2323.     | DAYZONE =
  2324.         {ourzone = $1; daylight = DAYLIGHT;};
  2325.  
  2326. dyspec:    DAY =
  2327.         {dayord = 1; dayreq = $1;}
  2328.     | DAY ',' =
  2329.         {dayord = 1; dayreq = $1;}
  2330.     | NUMBER DAY =
  2331.         {dayord = $1; dayreq = $2;};
  2332.  
  2333. dtspec:    NUMBER '/' NUMBER =
  2334.         {month = $1; day = $3;}
  2335.     | NUMBER '/' NUMBER '/' NUMBER =
  2336.         {month = $1; day = $3; year = $5;}
  2337.     | MONTH NUMBER =
  2338.         {month = $1; day = $2;}
  2339.     | MONTH NUMBER ',' NUMBER =
  2340.         {month = $1; day = $2; year = $4;}
  2341.     | NUMBER MONTH =
  2342.         {month = $2; day = $1;}
  2343.     | NUMBER MONTH NUMBER =
  2344.         {month = $2; day = $1; year = $3;};
  2345.  
  2346.  
  2347. rspec:    NUMBER UNIT =
  2348.         {relsec +=  60L * $1 * $2;}
  2349.     | NUMBER MUNIT =
  2350.         {relmonth += $1 * $2;}
  2351.     | NUMBER SUNIT =
  2352.         {relsec += $1;}
  2353.     | UNIT =
  2354.         {relsec +=  60L * $1;}
  2355.     | MUNIT =
  2356.         {relmonth += $1;}
  2357.     | SUNIT =
  2358.         {relsec++;}
  2359.     | rspec AGO =
  2360.         {relsec = -relsec; relmonth = -relmonth;};
  2361. %%
  2362.  
  2363. static int mdays[12] =
  2364.     {31, 0, 31,  30, 31, 30,  31, 31, 30,  31, 30, 31};
  2365. #define epoch 1970
  2366.  
  2367. extern struct tm *localtime();
  2368. time_t dateconv(mm, dd, yy, h, m, s, mer, zone, dayflag)
  2369. int mm, dd, yy, h, m, s, mer, zone, dayflag;
  2370. {
  2371.     time_t tod, jdate;
  2372.     register int i;
  2373.     time_t timeconv();
  2374.  
  2375.     if (yy < 0) yy = -yy;
  2376.     if (yy < 100) yy += 1900;
  2377.     mdays[1] = 28 + (yy%4 == 0);
  2378.     if (yy < epoch || yy > 1999 || mm < 1 || mm > 12 ||
  2379.         dd < 1 || dd > mdays[--mm]) return (-1);
  2380.     jdate = dd-1;
  2381.         for (i=0; i<mm; i++) jdate += mdays[i];
  2382.     for (i = epoch; i < yy; i++) jdate += 365 + (i%4 == 0);
  2383.     jdate *= daysec;
  2384.     jdate += zone * 60L;
  2385.     if ((tod = timeconv(h, m, s, mer)) < 0) return (-1);
  2386.     jdate += tod;
  2387.     if (dayflag==DAYLIGHT || (dayflag==MAYBE&&localtime(&jdate)->tm_isdst))
  2388.         jdate += -1*60*60;
  2389.     return (jdate);
  2390. }
  2391.  
  2392. time_t dayconv(ord, day, now) int ord, day; time_t now;
  2393. {
  2394.     register struct tm *loctime;
  2395.     time_t tod;
  2396.     time_t daylcorr();
  2397.  
  2398.     tod = now;
  2399.     loctime = localtime(&tod);
  2400.     tod += daysec * ((day - loctime->tm_wday + 7) % 7);
  2401.     tod += 7*daysec*(ord<=0?ord:ord-1);
  2402.     return daylcorr(tod, now);
  2403. }
  2404.  
  2405. time_t timeconv(hh, mm, ss, mer) register int hh, mm, ss, mer;
  2406. {
  2407.     if (mm < 0 || mm > 59 || ss < 0 || ss > 59) return (-1);
  2408.     switch (mer) {
  2409.         case AM: if (hh < 1 || hh > 12) return(-1);
  2410.              return (60L * ((hh%12)*60L + mm)+ss);
  2411.         case PM: if (hh < 1 || hh > 12) return(-1);
  2412.              return (60L * ((hh%12 +12)*60L + mm)+ss);
  2413.         case 24: if (hh < 0 || hh > 23) return (-1);
  2414.              return (60L * (hh*60L + mm)+ss);
  2415.         default: return (-1);
  2416.     }
  2417. }
  2418. time_t monthadd(sdate, relmonth) time_t sdate, relmonth;
  2419. {
  2420.     struct tm *ltime;
  2421.     time_t dateconv();
  2422.     time_t daylcorr();
  2423.     int mm, yy;
  2424.  
  2425.     if (relmonth == 0) return 0;
  2426.     ltime = localtime(&sdate);
  2427.     mm = 12*ltime->tm_year + ltime->tm_mon + relmonth;
  2428.     yy = mm/12;
  2429.     mm = mm%12 + 1;
  2430.     return daylcorr(dateconv(mm, ltime->tm_mday, yy, ltime->tm_hour,
  2431.         ltime->tm_min, ltime->tm_sec, 24, ourzone, MAYBE), sdate);
  2432. }
  2433.  
  2434. time_t daylcorr(future, now) time_t future, now;
  2435. {
  2436.     int fdayl, nowdayl;
  2437.  
  2438.     nowdayl = (localtime(&now)->tm_hour+1) % 24;
  2439.     fdayl = (localtime(&future)->tm_hour+1) % 24;
  2440.     return (future-now) + 60L*60L*(nowdayl-fdayl);
  2441. }
  2442.  
  2443. static char *lptr;
  2444.  
  2445. yylex()
  2446. {
  2447.     extern int yylval;
  2448.     int sign;
  2449.     register char c;
  2450.     register char *p;
  2451.     char idbuf[20];
  2452.     int pcnt;
  2453.  
  2454.     for (;;) {
  2455.         while (isspace(*lptr)) lptr++;
  2456.  
  2457.         if (isdigit(c = *lptr) || c == '-' || c == '+') {
  2458.             if (c== '-' || c == '+') {
  2459.                 if (c=='-') sign = -1;
  2460.                 else sign = 1;
  2461.                 if (!isdigit(*++lptr)) {
  2462.                     /* yylval = sign; return (NUMBER); */
  2463.                     return yylex();    /* skip the '-' sign */
  2464.                 }
  2465.             } else sign = 1;
  2466.             yylval = 0;
  2467.             while (isdigit(c = *lptr++)) yylval = 10*yylval + c - '0';
  2468.             yylval *= sign;
  2469.             lptr--;
  2470.             return (NUMBER);
  2471.  
  2472.         } else if (isalpha(c)) {
  2473.             p = idbuf;
  2474.             while (isalpha(c = *lptr++) || c=='.')
  2475.                 *p++ = c;
  2476.             *p = '\0';
  2477.             lptr--;
  2478.             return (lookup(idbuf));
  2479.         }
  2480.  
  2481.         else if (c == '(') {
  2482.             pcnt = 0;
  2483.             do {
  2484.                 c = *lptr++;
  2485.                 if (c == '\0') return(c);
  2486.                 else if (c == '(') pcnt++;
  2487.                 else if (c == ')') pcnt--;
  2488.             } while (pcnt > 0);
  2489.         }
  2490.  
  2491.         else return (*lptr++);
  2492.     }
  2493. }
  2494.  
  2495. struct table {
  2496.     char *name;
  2497.     int type, value;
  2498. };
  2499.  
  2500. struct table mdtab[] = {
  2501.     {"January", MONTH, 1},
  2502.     {"February", MONTH, 2},
  2503.     {"March", MONTH, 3},
  2504.     {"April", MONTH, 4},
  2505.     {"May", MONTH, 5},
  2506.     {"June", MONTH, 6},
  2507.     {"July", MONTH, 7},
  2508.     {"August", MONTH, 8},
  2509.     {"September", MONTH, 9},
  2510.     {"Sept", MONTH, 9},
  2511.     {"October", MONTH, 10},
  2512.     {"November", MONTH, 11},
  2513.     {"December", MONTH, 12},
  2514.  
  2515.     {"Sunday", DAY, 0},
  2516.     {"Monday", DAY, 1},
  2517.     {"Tuesday", DAY, 2},
  2518.     {"Tues", DAY, 2},
  2519.     {"Wednesday", DAY, 3},
  2520.     {"Wednes", DAY, 3},
  2521.     {"Thursday", DAY, 4},
  2522.     {"Thur", DAY, 4},
  2523.     {"Thurs", DAY, 4},
  2524.     {"Friday", DAY, 5},
  2525.     {"Saturday", DAY, 6},
  2526.     {0, 0, 0}};
  2527.  
  2528. #define HRS *60
  2529. #define HALFHR 30
  2530. struct table mztab[] = {
  2531.     {"a.m.", MERIDIAN, AM},
  2532.     {"am", MERIDIAN, AM},
  2533.     {"p.m.", MERIDIAN, PM},
  2534.     {"pm", MERIDIAN, PM},
  2535.     {"nst", ZONE, 3 HRS + HALFHR},        /* Newfoundland */
  2536.     {"n.s.t.", ZONE, 3 HRS + HALFHR},
  2537.     {"ast", ZONE, 4 HRS},        /* Atlantic */
  2538.     {"a.s.t.", ZONE, 4 HRS},
  2539.     {"adt", DAYZONE, 4 HRS},
  2540.     {"a.d.t.", DAYZONE, 4 HRS},
  2541.     {"est", ZONE, 5 HRS},        /* Eastern */
  2542.     {"e.s.t.", ZONE, 5 HRS},
  2543.     {"edt", DAYZONE, 5 HRS},
  2544.     {"e.d.t.", DAYZONE, 5 HRS},
  2545.     {"cst", ZONE, 6 HRS},        /* Central */
  2546.     {"c.s.t.", ZONE, 6 HRS},
  2547.     {"cdt", DAYZONE, 6 HRS},
  2548.     {"c.d.t.", DAYZONE, 6 HRS},
  2549.     {"mst", ZONE, 7 HRS},        /* Mountain */
  2550.     {"m.s.t.", ZONE, 7 HRS},
  2551.     {"mdt", DAYZONE, 7 HRS},
  2552.     {"m.d.t.", DAYZONE, 7 HRS},
  2553.     {"pst", ZONE, 8 HRS},        /* Pacific */
  2554.     {"p.s.t.", ZONE, 8 HRS},
  2555.     {"pdt", DAYZONE, 8 HRS},
  2556.     {"p.d.t.", DAYZONE, 8 HRS},
  2557.     {"yst", ZONE, 9 HRS},        /* Yukon */
  2558.     {"y.s.t.", ZONE, 9 HRS},
  2559.     {"ydt", DAYZONE, 9 HRS},
  2560.     {"y.d.t.", DAYZONE, 9 HRS},
  2561.     {"hst", ZONE, 10 HRS},        /* Hawaii */
  2562.     {"h.s.t.", ZONE, 10 HRS},
  2563.     {"hdt", DAYZONE, 10 HRS},
  2564.     {"h.d.t.", DAYZONE, 10 HRS},
  2565.     {"bst", ZONE, 11 HRS},        /* Bering */
  2566.     {"b.s.t.", ZONE, 11 HRS},
  2567.     {"bdt", DAYZONE, 11 HRS},
  2568.     {"b.d.t.", DAYZONE, 11 HRS},
  2569.  
  2570.     {"gmt", ZONE, 0 HRS},
  2571.     {"g.m.t.", ZONE, 0 HRS},
  2572.  
  2573.     {"aest", ZONE, -10 HRS},    /* Australian Eastern Time */
  2574.     {"a.e.s.t.", ZONE, -10 HRS},
  2575.     {"aesst", DAYZONE, -10 HRS},    /* Australian Eastern Summer Time */
  2576.     {"a.e.s.s.t.", DAYZONE, -10 HRS},
  2577.     {"acst", ZONE, -(9 HRS + HALFHR)},    /* Australian Central Time */
  2578.     {"a.c.s.t.", ZONE, -(9 HRS + HALFHR)},
  2579.     {"acsst", DAYZONE, -(9 HRS + HALFHR)},    /* Australian Central Summer */
  2580.     {"a.c.s.s.t.", DAYZONE, -(9 HRS + HALFHR)},
  2581.     {"awst", ZONE, -8 HRS},        /* Australian Western Time */
  2582.     {"a.w.s.t.", ZONE, -8 HRS},    /* (no daylight time there, I'm told */
  2583.     {0, 0, 0}};
  2584.  
  2585. struct table unittb[] = {
  2586.     {"year", MUNIT, 12},
  2587.     {"month", MUNIT, 1},
  2588.     {"fortnight", UNIT, 14*24*60},
  2589.     {"week", UNIT, 7*24*60},
  2590.     {"day", UNIT, 1*24*60},
  2591.     {"hour", UNIT, 60},
  2592.     {"minute", UNIT, 1},
  2593.     {"min", UNIT, 1},
  2594.     {"second", SUNIT, 1},
  2595.     {"sec", SUNIT, 1},
  2596.     {0, 0, 0}};
  2597.  
  2598. struct table othertb[] = {
  2599.     {"tomorrow", UNIT, 1*24*60},
  2600.     {"yesterday", UNIT, -1*24*60},
  2601.     {"today", UNIT, 0},
  2602.     {"now", UNIT, 0},
  2603.     {"last", NUMBER, -1},
  2604.     {"this", UNIT, 0},
  2605.     {"next", NUMBER, 2},
  2606.     {"first", NUMBER, 1},
  2607.     /* {"second", NUMBER, 2}, */
  2608.     {"third", NUMBER, 3},
  2609.     {"fourth", NUMBER, 4},
  2610.     {"fifth", NUMBER, 5},
  2611.     {"sixth", NUMBER, 6},
  2612.     {"seventh", NUMBER, 7},
  2613.     {"eigth", NUMBER, 8},
  2614.     {"ninth", NUMBER, 9},
  2615.     {"tenth", NUMBER, 10},
  2616.     {"eleventh", NUMBER, 11},
  2617.     {"twelfth", NUMBER, 12},
  2618.     {"ago", AGO, 1},
  2619.     {0, 0, 0}};
  2620.  
  2621. struct table milzone[] = {
  2622.     {"a", ZONE, 1 HRS},
  2623.     {"b", ZONE, 2 HRS},
  2624.     {"c", ZONE, 3 HRS},
  2625.     {"d", ZONE, 4 HRS},
  2626.     {"e", ZONE, 5 HRS},
  2627.     {"f", ZONE, 6 HRS},
  2628.     {"g", ZONE, 7 HRS},
  2629.     {"h", ZONE, 8 HRS},
  2630.     {"i", ZONE, 9 HRS},
  2631.     {"k", ZONE, 10 HRS},
  2632.     {"l", ZONE, 11 HRS},
  2633.     {"m", ZONE, 12 HRS},
  2634.     {"n", ZONE, -1 HRS},
  2635.     {"o", ZONE, -2 HRS},
  2636.     {"p", ZONE, -3 HRS},
  2637.     {"q", ZONE, -4 HRS},
  2638.     {"r", ZONE, -5 HRS},
  2639.     {"s", ZONE, -6 HRS},
  2640.     {"t", ZONE, -7 HRS},
  2641.     {"u", ZONE, -8 HRS},
  2642.     {"v", ZONE, -9 HRS},
  2643.     {"w", ZONE, -10 HRS},
  2644.     {"x", ZONE, -11 HRS},
  2645.     {"y", ZONE, -12 HRS},
  2646.     {"z", ZONE, 0 HRS},
  2647.     {0, 0, 0}};
  2648.  
  2649. lookup(id) char *id;
  2650. {
  2651. #define gotit (yylval=i->value,  i->type)
  2652. #define getid for(j=idvar, k=id; *j++ = *k++; )
  2653.  
  2654.     char idvar[20];
  2655.     register char *j, *k;
  2656.     register struct table *i;
  2657.     int abbrev;
  2658.  
  2659.     getid;
  2660.     if (strlen(idvar) == 3) abbrev = 1;
  2661.     else if (strlen(idvar) == 4 && idvar[3] == '.') {
  2662.         abbrev = 1;
  2663.         idvar[3] = '\0';
  2664.     }
  2665.     else abbrev = 0;
  2666.  
  2667.     if (islower(*idvar)) *idvar = toupper(*idvar);
  2668.  
  2669.     for (i = mdtab; i->name; i++) {
  2670.         k = idvar;
  2671.         for (j = i->name; *j++ == *k++;) {
  2672.             if (abbrev && j==i->name+3) return gotit;
  2673.             if (j[-1] == 0) return gotit;
  2674.         }
  2675.     }
  2676.  
  2677.     getid;
  2678.     for (i = mztab; i->name; i++)
  2679.         if (strcmp(i->name, idvar) == 0) return gotit;
  2680.  
  2681.     for (j = idvar; *j; j++) if (isupper(*j)) *j = tolower(*j);
  2682.     for (i=mztab; i->name; i++)
  2683.         if (strcmp(i->name, idvar) == 0) return gotit;
  2684.  
  2685.     getid;
  2686.     for (i=unittb; i->name; i++)
  2687.         if (strcmp(i->name, idvar) == 0) return gotit;
  2688.  
  2689.     if (idvar[strlen(idvar)-1] == 's') idvar[strlen(idvar)-1] = '\0';
  2690.     for (i=unittb; i->name; i++)
  2691.         if (strcmp(i->name, idvar) == 0) return gotit;
  2692.  
  2693.     getid;
  2694.     for (i = othertb; i->name; i++)
  2695.         if (strcmp(i->name, idvar) == 0) return gotit;
  2696.  
  2697.     getid;
  2698.     if (strlen(idvar) == 1 && isalpha(*idvar)) {
  2699.         if (isupper(*idvar)) *idvar = tolower(*idvar);
  2700.         for (i = milzone; i->name; i++)
  2701.             if (strcmp(i->name, idvar) == 0) return gotit;
  2702.     }
  2703.  
  2704.     return(ID);
  2705. }
  2706.  
  2707. time_t getdate(p, now) char *p; struct timeb *now;
  2708. {
  2709. #define mcheck(f)    if (f>1) err++
  2710.     time_t monthadd();
  2711.     int err;
  2712.     struct tm *lt;
  2713.     struct timeb ftz;
  2714.  
  2715.     time_t sdate, tod;
  2716.  
  2717.     lptr = p;
  2718.     if (now == ((struct timeb *) NULL)) {
  2719.         now = &ftz;
  2720.         ftime(&ftz);
  2721.     }
  2722.     lt = localtime(&now->time);
  2723.     year = lt->tm_year;
  2724.     month = lt->tm_mon+1;
  2725.     day = lt->tm_mday;
  2726.     relsec = 0; relmonth = 0;
  2727.     timeflag=zoneflag=dateflag=dayflag=relflag=0;
  2728.     ourzone = now->timezone;
  2729.     daylight = MAYBE;
  2730.     hh = mm = ss = 0;
  2731.     merid = 24;
  2732.  
  2733.     if (err = yyparse()) return (-1);
  2734.  
  2735.     mcheck(timeflag);
  2736.     mcheck(zoneflag);
  2737.     mcheck(dateflag);
  2738.     mcheck(dayflag);
  2739.  
  2740.     if (err) return (-1);
  2741.  
  2742.     if (dateflag || timeflag || dayflag) {
  2743.         sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,daylight);
  2744.         if (sdate < 0) return -1;
  2745.     }
  2746.     else {
  2747.         sdate = now->time;
  2748.         if (relflag == 0)
  2749.             sdate -= (lt->tm_sec + lt->tm_min*60 +
  2750.                 lt->tm_hour*(60L*60L));
  2751.     }
  2752.  
  2753.     sdate += relsec;
  2754.     sdate += monthadd(sdate, relmonth);
  2755.  
  2756.     if (dayflag && !dateflag) {
  2757.         tod = dayconv(dayord, dayreq, sdate);
  2758.         sdate += tod;
  2759.     }
  2760.  
  2761.     return sdate;
  2762. }
  2763.  
  2764. yyerror(s) char *s;
  2765. {}
  2766. !E!O!F!
  2767.  
  2768. echo Part 2 of 7 extracted.
  2769.  
  2770.  
  2771.